article

Jason Lightfoot avatar image
3 Likes"
Jason Lightfoot posted Jason Lightfoot edited

Pre-empting Process Flow Task Sequences


This example model was created to clarify pre-emption of task sequences created in process flows. Specifically it will show:

1) that pre-empting of task sequences generated in a process flow does not require the token generating the sequence to be pre-empted.

2) that you can push a partially created sequence to a tasksequence list type.

3) how to use recursive calls to a sub flow.

and afterwards:

4) how the milestone task can be used in a PF generated task sequence

5) the use a task type nodefunction

tepreemptifcloser.gif

Each queue is a member of the object process flow shown in the picture. Each generates a box along with a job to take it to another queue and pulls an initial task executer from the list of FreeTEs. The first task to travel and collect the box is preemptable and so we push the task sequence to a Premptable Job list before we add that travel task and pull it off the list when the task has completed. The rest of the task sequence is a standard load, travel and unload set of tasks.

When the job is complete we know that the TE is free and could preempt another TE - which could be desired if the newly free TE is closer to the pickup queue than the one currently assigned. The CheckPreempt subflow is called with a label referencing the TE that has become free. This TE may not be the original TE that we pulled from the list of FreeTEs when the job was started, and so we discover the current TE by looking for the task sequence's owner object - done with the function findownerobject() since it does not cache the value in the same way ownerobject() does, and we could have had more than two TEs assigned to this tasksequence. Since the task sequence gets destroy I do this in the assign labels activity before we finish the ts:

1690112344649.png

The Check Preempt subtask first tries to pull a preemptable job where the invoking TE is closer than the current executer of that job, and chooses the one where it is the most pronounced difference. The taskssequence list type has the distance field prepopulated and from that the two other field expressions otherDistance and howMuchCloser are derived.

1690112645099.png

If no task sequence is chosen then we push the finishing TE to the FreeTEs list.

If we choose a task sequence to preempt then we first label the token with the otherTE and the preempt the task sequence with a simple zero delay task. The we reDispatch the task sequence to the te that is calling Check Preempt. Since we now know that we've freed the otherTE from the task sequence it had we can invoke the Check Preempt subflow for that task executer, knowing that it will either get put onto the FreeTE list or get another task sequence and preempt another TE. This the is a recursive subflow call with the exit condition being that no preempatable tasksequence is found.

Note that no token preemption from activities takes place and this is because the tasksequence is still tied to the token and its activity, which will still receive the call back when a task is complete, regardless of which task executer actioned the task.

TEpreemptIfCloser1.fsm

Next: Changing colors to indicate preemptable TEs and their destination - using milestone and nodefunction tasks.

tepreemptifcloser2.gif

To better see the allocation and preempt activities we'll now change the model such that the TE color reflects the following:

  • White when idle
  • Gray when busy and not preemptable
  • Matching the pickup queue's color when preemptable.

First of all I defined two user commands - one to set the color of the TE (setTEcolor) and another (commandNode) to get the executable node of a user commands. This is so that I can add the fn() SetColor activity (it's a custom task of type nodefunction) ; specify the function using:

commandNode("setTEcolor")

and pass in the queue color as parameter 2 (parameter1 will be the TE that is executing this task).

1690116605442.png

This means the user command code is just:

Object te=param(1);
Color col=param(2);
te.color=col;


The milestone task allows us to define a set of tasks that need to be repeat if the TE gets pre-empted. It's added again using the Custom Task activity and selecting the type as Milestone and has a parameter to specify the number of subsequent tasks that should be considered within the preemption range that will trigger tasks to be repeated.

1690116378593.png

Since we want the Travel preemption to retrigger the setting of the color we set the range to 2. However since the token only needs to be notified when the travel task is complete that it should go on to the next process, and until then wait in the travel task we can uncheck the "Wait Until Complete" box of the Milestone and fn() SetColor activities:

1690117064922.png

If you don't clear this for those two tasks we expect some misbehavior/desynchonization with the token.

Finally there needs to be a resettrigger on the TE to set the color to white and a regular Change Visual activity after the pickup point is reached to set it to gray.

Note I prefer the use of commands to sending messages, which would be another option, mostly because users can tell the intent of the call without having to inspect the message code.

TEpreemptifCloser2.fsm

tokenspreemptionmilestone tasktasksequence preemption
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Article

Contributors

jason.lightfoot contributed to this article

Related Articles