Skip to main content
Kinetic Community

Updated Junction Logic

In Kinetic Task versions 4.0 and 3.2 we have updated the logic of Junction nodes due to popular demand.  This article talks about the motivations for and implications of this change.

Old Way

To really understand the motivation for this change we should review the behavior of junctions in previous versions of Kinetic Task.

Junction Use Case

Junctions were added to accommodate cases where the process needs to wait until multiple branches are complete but the number of branches that actually process varies from run to run. In the tree shown below, up to three work orders may be processed but not necessarily always three and our requirements state that the process must wait until all of them that should be processed are completed.

junction.png

Why not use a Join?

Even though there are three types of joins to choose from (any, all, and some) none of them are able to solve this problem. A join on any does not work because there would likely be cases where the process continues while another work order is still deferred. A join on all does not get the job done because cases where one or two work orders need to be processed would never result in completing the join. Finally, since a join on some requires us to configure the number of branches to wait for (which we cannot know when configuring the node) we are left with no other options. This is the case for junctions.

How do Junctions do it?

Junctions solve this problem by counting branches that evaluate to false in addition to branches that are processed actively. For example lets say that the Office? and Laptop? connectors evaluate to true and the Phone? connector evaluates to false. In this case the engine will create the office and laptop deferred work orders. When the Phone? connector evaluates to false it does not actively process any of the nodes on its branch, so it does not create the phone work order, but it does continue to the junction and mark that branch complete. Once the two work orders are completed they will continue to the junction and complete the remaining two branches. Since all three branches have been completed the junction will continue at the proper time.

Wait... There's a problem?

The way junctions were initially implemented was to continue when all of the processing prior was complete regardless of what any of the connectors evaluated to.  When considering the junction starting from the Approval node in the example above, it works as intended.  But suppose that the Requires Fulfillment connector prior to that evaluated to false.  Even though the connector evaluates to false we still process those branches (not actively) and eventually complete the junction.  When the junction is completed it will send the notification, for a part of the process that we thought would never be reached.

Now imagine a tree, much larger and more complex than the one shown above. And imagine that seemingly random nodes that should never be reached are being processed. What a nightmare. The junction was despised and unused which made the developers sad. It had to be fixed.

New and Improved

junction.png

Like stated above, the junction works as expected assuming that we have reached and processed the Approval node. It is cases where the Approval node was not reached and processed actively that we do not want the junction to continue. So in this example when the junction is completed, before continuing it should check to see whether or not the Approval node was processed. If so, it should continue processing actively, otherwise it should not continue.

The Approval node is special because it is where the process splits into the branches that are then merged at the junction.  The developers refer to it as the closest common ancestor.  So now, every time a junction is completed it checks the closest common ancestor to determine whether or not to continue.

Side Note

Before updating the junction logic there was a work around that we would suggest to achieve this same behavior.  It involves adding a connector expression to the connector immediately following the junction. The expression would check to see whether or not the closest common ancestor was executed. Below is an example of what this expression would look like for the example above.

@results.has_key?('Approval')

This is the same exact logic that is now automatically taking place in the junction handler. If you have used this work around there is no need to worry, when you update Task this sort of expression has no effect and your process should behave the same way.