OCSMP Model User study materials
OCSMP Model User study resources

The Palletizer That Stalls One Cycle in Seven

OCSMP Model User · Put your knowledge to work in context.

All case studies

The Palletizer That Stalls One Cycle in Seven

A palletizer activity runs a cycle: grip a carton, index the conveyor, place the carton. After 'Carton present' a ForkNode splits control into two concurrent branches. Branch A closes the gripper and flows straight into a JoinNode. Branch B enters a DecisionNode: guard [conveyor_ready] leads to 'Index conveyor' and then to the JoinNode; the else path leads to 'Signal operator' and terminates at a FlowFinalNode. The JoinNode's controlOperator is and, and its single outgoing edge feeds 'Place carton'. On the floor roughly 15% of cycles hang after the gripper closes; the conveyor sits idle and no fault is logged. The carton-present event fires every 4 s, indexing takes 3 s, and a separate object flow feeds Carton tokens into 'Place carton'.

1. Explain the stall. Is the JoinNode defective, and what token accounting produces the hang?

Read the worked answer

The join is doing exactly what an and-join must do; the defect is upstream.

  • An and-JoinNode enables its outgoing edge only when a token is offered on every incoming edge, and it consumes one token from each.
  • On cycles where conveyor_ready is false, branch B's token reaches 'Signal operator' and is then consumed by the FlowFinalNode. A FlowFinal consumes the token at that node and propagates nothing.
  • Branch A's token therefore parks at the join indefinitely. 'Place carton' is never enabled, and each subsequent cycle's fork deposits another token on branch A that also parks there. The activity deadlocks silently, which is why nothing is logged.

The 15% stall rate is consistent with the fraction of cycles where the guard fails (3 s of indexing against a 4 s arrival period). Note that the choice of terminator carries meaning: swapping the FlowFinal for an ActivityFinalNode would not fix the model - it would terminate the whole activity invocation, converting a silent stall into a hard stop.

2. Propose a corrected model. What must be decided before any node is edited?

Read the worked answer

First decide what the else path means, because two very different fixes are defensible.

(a) Operator notification is asynchronous and must not block the cycle. Model 'Signal operator' as a SendSignalAction and let the flow continue from it into the join. Both branches then reach the join and it fires. Caveat: the join fires as soon as the send completes - before indexing - so the join no longer guarantees what the reviewer will assume it guarantees. Acceptable only if 'Place carton' does not actually depend on the conveyor having indexed.

(b) Indexing really is a precondition for placing. Then indexing must not sit on a parallel branch at all. Remove the fork, put the decision before the fork, and route the not-ready case back through a wait (a loop with a time or signal event) until the guard passes; fork only for work that always runs.

Either way, state the else guard explicitly rather than relying on the implicit default, and confirm the Carton object flow is joined consistently with the control tokens so a carton cannot be placed without having been gripped.

3. A colleague proposes simply setting the JoinNode's controlOperator to or. Evaluate that change.

Read the worked answer

It makes the symptom disappear and the model wrong.

An or-join fires on the first token to arrive and does not wait for, or consume, the others. Consequences:

  • 'Place carton' can fire on a cycle where the gripper has closed but the conveyor path was abandoned - a race, not a synchronization.
  • The unconsumed branch A token stays pending and can pair with the next cycle's token, so 'Place carton' may fire twice for one carton, or fire with no Carton token available on the object flow.
  • The model stops recording that the conveyor path is optional.

You have traded a deadlock for a lost-token defect that only shows up under load. If the true intent is 'index if possible, place anyway', express that as a decision plus a merge after the join, or as an interruptible region - never by weakening the join operator, which is a statement about synchronization requirements.