Layer the handling: technical retries inside the service flow, business-level alternatives in the BPD, and a manual "repair" path for what is left.
- Service flow level - retry with backoff: wrap the call in a loop with a counter and a wait; catch the error with an error boundary event on the integration step (or a try/catch in a script), decide whether the error is transient (timeouts, 502 / 503 / 429) and retry, otherwise throw a typed error.
// service flow "Call pricing service (resilient)" - steps: [Init] -> [Call REST] --error--> [Classify] -> retry? -> [Wait] -> [Call REST] ... -> [Throw]
// Init
tw.local.attempt = 0; tw.local.maxAttempts = 4;
// Classify (script on the error path; tw.local.error mapped from the boundary event)
var msg = String(tw.local.error ? tw.local.error.errorText || tw.local.error : "");
tw.local.transient = /timed? ?out|503|502|429|Connection refused|UnknownHost/i.test(msg);
tw.local.attempt++;
tw.local.retry = tw.local.transient && tw.local.attempt < tw.local.maxAttempts;
// Wait (script) - exponential backoff, capped; short waits are fine inside a service flow, long ones belong in the BPD (timer)
java.lang.Thread.sleep(Math.min(30000, 1000 * Math.pow(2, tw.local.attempt)));
// Throw (script) - a typed error the BPD can catch
throw new Error("PRICING_UNAVAILABLE: " + msg.substring(0, 200));- BPD level - alternatives and long waits: an error boundary event on the activity (catch by error code or catch all) routes to a fallback (use a cached price, a manual pricing task, or a timer of an hour followed by a loop back to the activity - long retries belong in the BPD because the instance is persisted while waiting and the Event Manager wakes it up).
- Compensation: BPMN compensation is not automatic in BAW; model it explicitly - a "rollback" path that reverses earlier side effects (cancel the reservation, reverse the booking) using the ids stored in instance variables; make every integration idempotent (client-generated request ids) so that a retry after a timeout does not duplicate an order.
- Manual repair: whatever remains failed shows up in Process Admin; use Retry (re-runs the failed step with the same data) after the external system is back, or route failures to an "Operations" task with a coach that lets an operator fix the data and choose retry / skip / abort - far better than administrators editing variables.
BPD "Order handling"
[Price order] (service: Call pricing service (resilient))
error boundary (PRICING_UNAVAILABLE) -> [Wait 1 hour] (timer intermediate event) -> loop back to [Price order] (up to 24 loops, counter in tw.local.priceRetries)
error boundary (catch all) -> [Operations task: fix pricing] (team Operations; outputs action=retry|manual price|cancel)Rules: never retry non-idempotent calls blindly; log each attempt with the request id; alert (e-mail / event) when the retry budget is exhausted; keep the retry parameters in environment variables or EPVs so that operations can tune them without redeploying; and use Stay on page service calls in coaches for retries of user-triggered calls rather than failing the whole task.
References