Looks like I have the need to have workunits for PO Maintenance to run one at a time instead of having some run simultaneously. Anyone else run into this issue before and how to set that up?
Good morning Todd,
I am not familiar with the PO Maintenance flow you are discussing; so I will just assume this is a flow that accesses a set of records and if two flows execute at the same time they could step on each other.
Some of the answers, or the best answer for you will somewhat depend on what version of Landmark you are running. Can you run: univver -v from a landmark command and verify your version? Thanks.
1. If you are scheduling this flow; minimize risk of two flows executing simultaneously.
-- Make sure your "Action Failure" is set to "Run Once" strategy with an adequate setting for Threshold Minutes.
Example:
- My flow takes 5 minutes to execute
- I want to run it every 10 minutes.
- If I schedule this with a threshold of 4 minutes; with a "Run Once" strategy ... if I miss my schedule due to an outage/busy system (max active actions) by more than 4 minutes I will NOT execute that run. If I miss by less than that I will still execute that schedule
2. This doesn't prevent two flows from executing simultaneously though as someone could manually trigger/restart a workunit. Assuming you are on v11 we are going to design a "sub process" that we can use in other flows.
i) In the start node create a variable of type "Array" called "workunits"
ii) Add a Landmark Transaction Node to the flow; connect start node to it. Copy paste this into the Landmark Transaction String:
_dataArea="<!LPSDataArea>" & _module="pfi" & _objectName="PfiWorkunit" & _actionName="Find" & _actionOperator="NONE" & _actionType="MultipleRecordQuery" & _runAsUser="" & _authenticatedUser="" & _pageSize="30" & _filterString=FlowDefinition="<!ProcessName>" and (Status=2 or Status=10) & _relationName="" & _setName="" & _asOfDate="" & _effectiveDate="" & Status & PfiWorkunit
iii) In the middle of that Transaction; between start and end of the query add an assign node.
Add a javascript expression in the assign node with the following:
workunits.push(LMTxn5400_PfiWorkunit);
iv) Add a Branch Node to the flow
Link the end of the Landmark Transaction to the branch node.
v) Use Connection to connect Branch node to end node. When the branch condition pops up name it "currentWorkunit" and put this in the evaluation:
Math.min.apply(Math, workunits) == WorkUnit
vi) Add a Wait Node to your flow
-- put 15 seconds in the wait time
-- make sure "Keep Workunit active" is not checked
vii) Connect your branch node to your wait node. When the branch condition pops up name it "NotCurrentWorkunit" and put this in the evaluation:
true
ix) Connect your wait node up to the start of the Landmark Transaction ... should look like this.
I saved a copy here as WorkunitLimiter.xml; download that rename to WorkunitLimiter.lpd
[View:/cfs-file/__key/communityserver-discussions-components-files/57/WorkuitLimiter.xml:320:240]
[View:/cfs-file/__key/communityserver-discussions-components-files/57/WorkunitLimiter.xml:320:240]
NOTES:
This type of flow is making use of a few things to work.
We know workunits are unique, and are added in numerical order by an Auto Sequence so we know the lowest number workunit was added to the system first and should be processed in a FIFO order. We also know that before a workunit can even begin processing its start node; its status is already changed to PROCESSING.
So leveraging a Landmark transaction, we are going to query workunits to return us any workunits where the flow name matches ours. (ProcessName) is a variable that contains the name of the flow so no need to change it should you have multiple types of flows that should be singleton workunits. Add a filter of Status=2 or Status=10 gives us a list of workunits that are "PROCESSING" or "WAITING"
We push each workunit to an array; then use the Math.min function to return us the lowest value in our array. If this matches our workunit number ... it's our turn to process. If its not our turn to process we goto a "wait node for 15 seconds"
If the previous workunit completed at that point ... when we requery workunits we would be the min record in our array and would process.
------------------------------------------------------------------------------------
MODIFICATION:
Instead of creating "workunits" array in Start node; add an assign node between "Start" and "Landmark"; then use a javascript expression:
var workunits = [];
Your wait node should direct to this assign node to make sure we blank out the values previously loaded in the array.
**** My system seems to blank that array when the flow stops at the wait node; but it probably shouldn't. If this was a regular flow instead of a subroutine I am not sure it would.