@nanobpm/nano-workforce 0.120.0 → 0.120.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/app/capabilityNeed.test.ts +4 -2
- package/app/capabilityNeed.ts +3 -1
- package/app/deliveryGraphCompiler.test.ts +2 -2
- package/app/deliveryGraphCompiler.ts +63 -17
- package/app/deliveryRunner.test.ts +1 -0
- package/app/deliveryRunner.ts +16 -4
- package/app/feature.test.ts +3 -1
- package/app/feature.ts +9 -0
- package/app/featureReadiness.test.ts +7 -4
- package/app/featureReadiness.ts +8 -3
- package/app/plan.test.ts +1 -1
- package/app/plan.ts +9 -0
- package/app/planFanoutPreflight.test.ts +12 -12
- package/app/planLowering.test.ts +2 -0
- package/app/planLowering.ts +7 -2
- package/app/readiness.test.ts +9 -0
- package/app/readiness.ts +25 -0
- package/app/service.ts +8 -1
- package/biome.json +24 -1
- package/e2e/delivery-graph.e2e.ts +2 -1
- package/e2e/feature-preflight.e2e.ts +2 -0
- package/e2e/inter-epic-dependency.e2e.ts +7 -1
- package/e2e/plan-fanout-preflight.e2e.ts +2 -0
- package/e2e/readiness-gate.e2e.ts +27 -11
- package/package.json +1 -1
- package/resources/processes/feature.bpmn +168 -52
- package/resources/processes/plan-fanout.bpmn +168 -52
- package/resources/processes/readiness-gate.bpmn +194 -84
- package/workers/readiness-probe/worker.test.ts +82 -238
- package/workers/readiness-probe/worker.ts +46 -128
package/app/service.ts
CHANGED
|
@@ -70,6 +70,7 @@ import {
|
|
|
70
70
|
probeOnce,
|
|
71
71
|
READINESS_READY_MESSAGE,
|
|
72
72
|
type ReadinessProbe,
|
|
73
|
+
readinessPollEvery,
|
|
73
74
|
readinessTimeout,
|
|
74
75
|
} from "./readiness.ts";
|
|
75
76
|
import { clampNudgeMinutes, reviewWaitTimeout } from "./reviewWait.ts";
|
|
@@ -1688,6 +1689,10 @@ function capabilityGateTimeout(env: Record<string, string | undefined>): string
|
|
|
1688
1689
|
return readinessTimeout({ kind: "capability", target: "" } satisfies ReadinessProbe, env);
|
|
1689
1690
|
}
|
|
1690
1691
|
|
|
1692
|
+
function capabilityGatePollEvery(env: Record<string, string | undefined>): string {
|
|
1693
|
+
return readinessPollEvery({ kind: "capability", target: "" } satisfies ReadinessProbe, env);
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1691
1696
|
/** Capability-edge reconcile pass (issue #289). The host half of the "consumer readiness edge":
|
|
1692
1697
|
* plan-fanout's per-task fan-out parks at the `wait-caps-resolved` message barrier for any task that
|
|
1693
1698
|
* declared cross-repo capability `needs` (049_plan_task_needs.sql). Here we reconcile, on EVERY pass
|
|
@@ -1721,6 +1726,7 @@ export async function pollCapabilityGatesImpl(
|
|
|
1721
1726
|
) {
|
|
1722
1727
|
const gateTable = capabilityGates(data);
|
|
1723
1728
|
const probeTimeout = capabilityGateTimeout(env);
|
|
1729
|
+
const probePollEvery = capabilityGatePollEvery(env);
|
|
1724
1730
|
for (const plan of await plans(data).all()) {
|
|
1725
1731
|
const planKey = plan.plan_key;
|
|
1726
1732
|
const processKey = plan.process_key;
|
|
@@ -1757,7 +1763,7 @@ export async function pollCapabilityGatesImpl(
|
|
|
1757
1763
|
// need as unresolved (it can only clear once the handle is corrected on a re-plan).
|
|
1758
1764
|
let probeInput: ReturnType<typeof capabilityNeedToProbeInput>;
|
|
1759
1765
|
try {
|
|
1760
|
-
probeInput = capabilityNeedToProbeInput(need, { planKey, taskId, probeTimeout });
|
|
1766
|
+
probeInput = capabilityNeedToProbeInput(need, { planKey, taskId, probeTimeout, probePollEvery });
|
|
1761
1767
|
} catch (err) {
|
|
1762
1768
|
if (err instanceof UnresolvableCapabilityRefError) {
|
|
1763
1769
|
if (!row) {
|
|
@@ -1808,6 +1814,7 @@ export async function pollCapabilityGatesImpl(
|
|
|
1808
1814
|
variables: {
|
|
1809
1815
|
gateKey: probeInput.gateKey,
|
|
1810
1816
|
probeTimeout: probeInput.probeTimeout,
|
|
1817
|
+
probePollEvery: probeInput.probePollEvery,
|
|
1811
1818
|
onTimeout: probeInput.onTimeout,
|
|
1812
1819
|
probe: probeInput.probe,
|
|
1813
1820
|
},
|
package/biome.json
CHANGED
|
@@ -137,5 +137,28 @@
|
|
|
137
137
|
],
|
|
138
138
|
"formatter": {
|
|
139
139
|
"enabled": false
|
|
140
|
-
}
|
|
140
|
+
},
|
|
141
|
+
"overrides": [
|
|
142
|
+
{
|
|
143
|
+
"includes": [
|
|
144
|
+
"workers/readiness-probe/**"
|
|
145
|
+
],
|
|
146
|
+
"linter": {
|
|
147
|
+
"rules": {
|
|
148
|
+
"style": {
|
|
149
|
+
"noRestrictedGlobals": {
|
|
150
|
+
"level": "error",
|
|
151
|
+
"options": {
|
|
152
|
+
"deniedGlobals": {
|
|
153
|
+
"setTimeout": "Use engine BPMN timers; readiness-probe must be single-shot.",
|
|
154
|
+
"setInterval": "Use engine BPMN timers; readiness-probe must be single-shot.",
|
|
155
|
+
"Date": "Use engine BPMN timers; readiness-probe must not read wall-clock time."
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
]
|
|
141
164
|
}
|
|
@@ -172,7 +172,7 @@ describe("delivery-graph runner — engine-native execution (S4)", () => {
|
|
|
172
172
|
],
|
|
173
173
|
edges: [],
|
|
174
174
|
};
|
|
175
|
-
const run = await runDeliveryGraph(app.engine, graph, { probeTimeout: "PT2S", escalationSlaTimeout: "PT1H" });
|
|
175
|
+
const run = await runDeliveryGraph(app.engine, graph, { probeTimeout: "PT2S", probePollEvery: "PT1S", escalationSlaTimeout: "PT1H" });
|
|
176
176
|
assert.ok(run.ok, `graph should deploy + run, got ${JSON.stringify(run)}`);
|
|
177
177
|
await app.settle();
|
|
178
178
|
|
|
@@ -188,6 +188,7 @@ describe("delivery-graph runner — engine-native execution (S4)", () => {
|
|
|
188
188
|
// wait is BOUNDED — its poll budget elapses and it escalates onto a human-completable task, parking
|
|
189
189
|
// for a human rather than silently wedging or falsely resolving.
|
|
190
190
|
assert.ok(!takenFlows(app).some((f) => f.endsWith("->End")), "the wait branch never falsely resolves to End");
|
|
191
|
+
await app.advanceTime(2_100);
|
|
191
192
|
const esc = (await app.engine.searchUserTasks({ state: "CREATED" })).filter((t) => t.elementId?.endsWith("__esc"));
|
|
192
193
|
assert.ok(
|
|
193
194
|
esc.length >= 1,
|
|
@@ -77,6 +77,7 @@ function featureVars(overrides: Record<string, unknown>): Record<string, unknown
|
|
|
77
77
|
customInstructions: null,
|
|
78
78
|
readinessProbes: null,
|
|
79
79
|
probeTimeout: null,
|
|
80
|
+
probePollEvery: null,
|
|
80
81
|
gateKey: null,
|
|
81
82
|
resolvedArtifacts: null,
|
|
82
83
|
...overrides,
|
|
@@ -129,6 +130,7 @@ describe("single-issue feature intake readiness gate (feature.bpmn, issue #295)"
|
|
|
129
130
|
},
|
|
130
131
|
],
|
|
131
132
|
probeTimeout: "PT30M",
|
|
133
|
+
probePollEvery: "PT15S",
|
|
132
134
|
gateKey: "feature-readiness:owner/repo#7",
|
|
133
135
|
}),
|
|
134
136
|
});
|
|
@@ -66,6 +66,7 @@ function planVars(overrides: Record<string, unknown>): Record<string, unknown> {
|
|
|
66
66
|
waveCount: 1,
|
|
67
67
|
readinessProbes: null,
|
|
68
68
|
probeTimeout: null,
|
|
69
|
+
probePollEvery: null,
|
|
69
70
|
gateKey: null,
|
|
70
71
|
resolvedArtifacts: null,
|
|
71
72
|
...overrides,
|
|
@@ -115,6 +116,7 @@ describe("inter-epic capability gate — adversarial (plan-fanout.bpmn, issue #2
|
|
|
115
116
|
variables: planVars({
|
|
116
117
|
readinessProbes: [redProbe()],
|
|
117
118
|
probeTimeout: "PT2S",
|
|
119
|
+
probePollEvery: "PT1S",
|
|
118
120
|
gateKey: "preflight:owner/repo#2",
|
|
119
121
|
}),
|
|
120
122
|
});
|
|
@@ -133,7 +135,8 @@ describe("inter-epic capability gate — adversarial (plan-fanout.bpmn, issue #2
|
|
|
133
135
|
!flows.includes("readiness-preflight->ensure-base-branch"),
|
|
134
136
|
"the gate HOLDS wave 0 — a parked dependent never reaches the fan-out head",
|
|
135
137
|
);
|
|
136
|
-
|
|
138
|
+
await app.advanceTime(2_100);
|
|
139
|
+
// The token is parked on the escalation user task after the engine-owned timeout, not lost.
|
|
137
140
|
const tasks = (await app.engine.searchUserTasks({ processInstanceKey })).filter(
|
|
138
141
|
(t) => t.elementId === "readiness-escalation-pf",
|
|
139
142
|
);
|
|
@@ -153,10 +156,12 @@ describe("inter-epic capability gate — adversarial (plan-fanout.bpmn, issue #2
|
|
|
153
156
|
variables: planVars({
|
|
154
157
|
readinessProbes: [redProbe()],
|
|
155
158
|
probeTimeout: "PT2S",
|
|
159
|
+
probePollEvery: "PT1S",
|
|
156
160
|
gateKey: "preflight:owner/repo#2",
|
|
157
161
|
}),
|
|
158
162
|
});
|
|
159
163
|
await app.settle();
|
|
164
|
+
await app.advanceTime(2_100);
|
|
160
165
|
|
|
161
166
|
const escalations = (await app.engine.searchUserTasks({ processInstanceKey })).filter(
|
|
162
167
|
(t) => t.elementId === "readiness-escalation-pf",
|
|
@@ -196,6 +201,7 @@ describe("inter-epic capability gate — adversarial (plan-fanout.bpmn, issue #2
|
|
|
196
201
|
}),
|
|
197
202
|
});
|
|
198
203
|
await app.settle();
|
|
204
|
+
await app.advanceTime(2_100);
|
|
199
205
|
|
|
200
206
|
// Parked on the escalation, no human acts. Before the SLA it has NOT proceeded.
|
|
201
207
|
const before = takenFlows(app);
|
|
@@ -65,6 +65,7 @@ function planVars(overrides: Record<string, unknown>): Record<string, unknown> {
|
|
|
65
65
|
waveCount: 1,
|
|
66
66
|
readinessProbes: null,
|
|
67
67
|
probeTimeout: null,
|
|
68
|
+
probePollEvery: null,
|
|
68
69
|
gateKey: null,
|
|
69
70
|
resolvedArtifacts: null,
|
|
70
71
|
...overrides,
|
|
@@ -116,6 +117,7 @@ describe("plan-fanout inter-epic capability preflight (plan-fanout.bpmn, issue #
|
|
|
116
117
|
},
|
|
117
118
|
],
|
|
118
119
|
probeTimeout: "PT30M",
|
|
120
|
+
probePollEvery: "PT15S",
|
|
119
121
|
gateKey: "preflight:owner/repo#2",
|
|
120
122
|
}),
|
|
121
123
|
});
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
// The probes are deterministic shell builtins (`true`/`false`) so the flow is hermetic — no
|
|
19
19
|
// network, no GitHub. GitHub transport is still forced offline to match the sibling e2es.
|
|
20
20
|
import assert from "node:assert/strict";
|
|
21
|
-
import {
|
|
22
|
-
import { tmpdir } from "node:os";
|
|
21
|
+
import { mkdirSync, rmSync } from "node:fs";
|
|
23
22
|
import { dirname, join, resolve } from "node:path";
|
|
24
23
|
import { after, before, describe, test } from "node:test";
|
|
25
24
|
import { fileURLToPath } from "node:url";
|
|
26
25
|
import { bootTestApp, type TestApp } from "@nanobpm/urban-testkit";
|
|
27
26
|
|
|
28
27
|
const APP_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
28
|
+
let dbSeq = 0;
|
|
29
29
|
|
|
30
30
|
const GITHUB_ENV_OVERRIDES: Record<string, string> = {
|
|
31
31
|
NANO_PR_GITHUB_TRANSPORT: "token",
|
|
@@ -49,7 +49,8 @@ function takenFlows(app: TestApp): string[] {
|
|
|
49
49
|
// Each scenario boots its own app so `takenSequenceFlows` (engine-global + cumulative) reflects
|
|
50
50
|
// exactly one instance's history.
|
|
51
51
|
async function boot(): Promise<{ app: TestApp; dbDir: string }> {
|
|
52
|
-
const dbDir =
|
|
52
|
+
const dbDir = join(APP_ROOT, ".test-artifacts", `nwf-readiness-${process.pid}-${dbSeq++}`);
|
|
53
|
+
mkdirSync(dbDir, { recursive: true });
|
|
53
54
|
const app = await bootTestApp(APP_ROOT, { env: { NANO_APP_DB_URL: `file:${join(dbDir, "app.db")}` } });
|
|
54
55
|
return { app, dbDir };
|
|
55
56
|
}
|
|
@@ -79,6 +80,7 @@ describe("nano-workforce artifact-readiness wait-gate (readiness-gate.bpmn)", ()
|
|
|
79
80
|
probe: { kind: "command", target: "true", poll: { everyMs: 5, timeoutMs: 5000, backoff: "fixed" } },
|
|
80
81
|
// A long engine timer that must NOT fire — readiness wins the race first.
|
|
81
82
|
probeTimeout: "PT30M",
|
|
83
|
+
probePollEvery: "PT15S",
|
|
82
84
|
onTimeout: "escalate",
|
|
83
85
|
},
|
|
84
86
|
});
|
|
@@ -90,8 +92,8 @@ describe("nano-workforce artifact-readiness wait-gate (readiness-gate.bpmn)", ()
|
|
|
90
92
|
`the gate released on the readiness signal (flows: ${flows.join(", ")})`,
|
|
91
93
|
);
|
|
92
94
|
assert.ok(
|
|
93
|
-
flows.includes("probe->probe-done"),
|
|
94
|
-
"the probe branch settled after publishing the readiness signal",
|
|
95
|
+
flows.includes("probe-loop->probe-done"),
|
|
96
|
+
"the probe loop branch settled after publishing the readiness signal",
|
|
95
97
|
);
|
|
96
98
|
// The gate never timed out — no escalation userTask exists.
|
|
97
99
|
const tasks = await app.engine.searchUserTasks({});
|
|
@@ -115,15 +117,16 @@ describe("nano-workforce artifact-readiness wait-gate (readiness-gate.bpmn)", ()
|
|
|
115
117
|
gateKey: "gate-timeout-1",
|
|
116
118
|
// `false` is never ready; a tiny local budget makes the worker exhaust fast (real time),
|
|
117
119
|
// leaving the ENGINE timer as the authoritative bound.
|
|
118
|
-
probe: { kind: "command", target: "false", poll: { everyMs:
|
|
120
|
+
probe: { kind: "command", target: "false", poll: { everyMs: 15_000, timeoutMs: 60_000, backoff: "fixed" } },
|
|
119
121
|
probeTimeout: "PT1M",
|
|
122
|
+
probePollEvery: "PT15S",
|
|
120
123
|
onTimeout: "escalate",
|
|
121
124
|
},
|
|
122
125
|
});
|
|
123
126
|
await app.settle();
|
|
124
127
|
|
|
125
|
-
// The wait has NOT hung and has NOT yet escalated: the probe
|
|
126
|
-
//
|
|
128
|
+
// The wait has NOT hung and has NOT yet escalated: the first single-shot probe returned not-ready,
|
|
129
|
+
// and the retry cadence is parked on the engine-owned poll timer.
|
|
127
130
|
const beforeTimer = await app.engine.searchUserTasks({ processInstanceKey });
|
|
128
131
|
assert.equal(
|
|
129
132
|
beforeTimer.filter((t) => t.elementId === "readiness-escalation").length,
|
|
@@ -133,9 +136,18 @@ describe("nano-workforce artifact-readiness wait-gate (readiness-gate.bpmn)", ()
|
|
|
133
136
|
const beforeFlows = takenFlows(app);
|
|
134
137
|
assert.ok(!beforeFlows.includes("wait-ready->gate-ready"), "a never-green probe never releases as ready");
|
|
135
138
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
+
await app.advanceTime(15_000);
|
|
140
|
+
const afterPoll = takenFlows(app);
|
|
141
|
+
assert.ok(afterPoll.includes("wait-poll->probe"), "the engine timer, not a worker sleep loop, schedules the next probe");
|
|
142
|
+
assert.equal(
|
|
143
|
+
(await app.engine.searchUserTasks({ processInstanceKey })).filter((t) => t.elementId === "readiness-escalation").length,
|
|
144
|
+
0,
|
|
145
|
+
"one poll interval only re-probes; it does not consume the timeout",
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
// Advancing past the engine timer is the ONLY thing that ends the wait. The timeout arm routes
|
|
149
|
+
// through one last empirical probe before the event-based gateway timer opens escalation.
|
|
150
|
+
await app.advanceTime(46_000);
|
|
139
151
|
|
|
140
152
|
const afterFlows = takenFlows(app);
|
|
141
153
|
assert.ok(
|
|
@@ -171,6 +183,7 @@ describe("nano-workforce artifact-readiness wait-gate (readiness-gate.bpmn)", ()
|
|
|
171
183
|
gateKey: "gate-abandon-1",
|
|
172
184
|
probe: { kind: "command", target: "false", poll: { everyMs: 5, timeoutMs: 40, backoff: "fixed" } },
|
|
173
185
|
probeTimeout: "PT1M",
|
|
186
|
+
probePollEvery: "PT15S",
|
|
174
187
|
onTimeout: "escalate",
|
|
175
188
|
},
|
|
176
189
|
});
|
|
@@ -209,6 +222,7 @@ describe("nano-workforce artifact-readiness wait-gate (readiness-gate.bpmn)", ()
|
|
|
209
222
|
gateKey: "gate-continue-1",
|
|
210
223
|
probe: { kind: "command", target: "false", poll: { everyMs: 5, timeoutMs: 40, backoff: "fixed" } },
|
|
211
224
|
probeTimeout: "PT1M",
|
|
225
|
+
probePollEvery: "PT15S",
|
|
212
226
|
onTimeout: "continue",
|
|
213
227
|
},
|
|
214
228
|
});
|
|
@@ -236,6 +250,7 @@ describe("nano-workforce artifact-readiness wait-gate (readiness-gate.bpmn)", ()
|
|
|
236
250
|
// Neither probe.onTimeout nor a top-level onTimeout is declared.
|
|
237
251
|
probe: { kind: "command", target: "false", poll: { everyMs: 5, timeoutMs: 40, backoff: "fixed" } },
|
|
238
252
|
probeTimeout: "PT1M",
|
|
253
|
+
probePollEvery: "PT15S",
|
|
239
254
|
},
|
|
240
255
|
});
|
|
241
256
|
await app.settle();
|
|
@@ -266,6 +281,7 @@ describe("nano-workforce artifact-readiness wait-gate (readiness-gate.bpmn)", ()
|
|
|
266
281
|
// The descriptor asks to continue; a stale top-level onTimeout says escalate. probe wins.
|
|
267
282
|
probe: { kind: "command", target: "false", onTimeout: "continue", poll: { everyMs: 5, timeoutMs: 40, backoff: "fixed" } },
|
|
268
283
|
probeTimeout: "PT1M",
|
|
284
|
+
probePollEvery: "PT15S",
|
|
269
285
|
onTimeout: "escalate",
|
|
270
286
|
},
|
|
271
287
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanobpm/nano-workforce",
|
|
3
|
-
"version": "0.120.
|
|
3
|
+
"version": "0.120.1",
|
|
4
4
|
"description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "main.ts",
|
|
@@ -39,23 +39,75 @@
|
|
|
39
39
|
<bpmn:startEvent id="pf_start" name="Awaiting readiness">
|
|
40
40
|
<bpmn:outgoing>pf_toProbe</bpmn:outgoing>
|
|
41
41
|
</bpmn:startEvent>
|
|
42
|
-
<bpmn:
|
|
42
|
+
<bpmn:subProcess id="preflight-probe-loop" name="Probe readiness loop">
|
|
43
43
|
<bpmn:extensionElements>
|
|
44
|
-
<zeebe:
|
|
45
|
-
|
|
46
|
-
<zeebe:
|
|
47
|
-
<zeebe:
|
|
48
|
-
|
|
44
|
+
<zeebe:ioMapping>
|
|
45
|
+
<zeebe:output source="=ready" target="ready" />
|
|
46
|
+
<zeebe:output source="=if (is defined(detail)) then detail else null" target="detail" />
|
|
47
|
+
<zeebe:output source="=if (is defined(resolvedArtifact)) then resolvedArtifact else null" target="resolvedArtifact" />
|
|
48
|
+
<zeebe:output source="=if (is defined(mergedSha)) then mergedSha else null" target="mergedSha" />
|
|
49
|
+
</zeebe:ioMapping>
|
|
49
50
|
</bpmn:extensionElements>
|
|
50
51
|
<bpmn:incoming>pf_toProbe</bpmn:incoming>
|
|
51
52
|
<bpmn:outgoing>pf_probed</bpmn:outgoing>
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
<bpmn:startEvent id="pf_loop_start" name="Start probe loop">
|
|
54
|
+
<bpmn:outgoing>pf_loop_toProbe</bpmn:outgoing>
|
|
55
|
+
</bpmn:startEvent>
|
|
56
|
+
<bpmn:serviceTask id="preflight-probe" name="Probe readiness">
|
|
57
|
+
<bpmn:extensionElements>
|
|
58
|
+
<zeebe:taskDefinition type="pr.readiness-probe" />
|
|
59
|
+
<zeebe:properties>
|
|
60
|
+
<zeebe:property name="io.nanobpm.dataEnvelope.in" value="ReadinessProbeIn" />
|
|
61
|
+
<zeebe:property name="io.nanobpm.dataEnvelope.out" value="ReadinessProbeOut" />
|
|
62
|
+
</zeebe:properties>
|
|
63
|
+
</bpmn:extensionElements>
|
|
64
|
+
<bpmn:incoming>pf_loop_toProbe</bpmn:incoming>
|
|
65
|
+
<bpmn:incoming>pf_pollBack</bpmn:incoming>
|
|
66
|
+
<bpmn:outgoing>pf_loop_probed</bpmn:outgoing>
|
|
67
|
+
</bpmn:serviceTask>
|
|
68
|
+
<bpmn:exclusiveGateway id="pf_loop_gw" name="ready?" default="pf_notReady">
|
|
69
|
+
<bpmn:incoming>pf_loop_probed</bpmn:incoming>
|
|
70
|
+
<bpmn:outgoing>pf_loop_ready</bpmn:outgoing>
|
|
71
|
+
<bpmn:outgoing>pf_notReady</bpmn:outgoing>
|
|
72
|
+
</bpmn:exclusiveGateway>
|
|
73
|
+
<bpmn:intermediateCatchEvent id="pf_wait_poll" name="Wait poll interval">
|
|
74
|
+
<bpmn:incoming>pf_notReady</bpmn:incoming>
|
|
75
|
+
<bpmn:outgoing>pf_pollBack</bpmn:outgoing>
|
|
76
|
+
<bpmn:timerEventDefinition id="ted_pf_probe_poll">
|
|
77
|
+
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=probePollEvery</bpmn:timeDuration>
|
|
78
|
+
</bpmn:timerEventDefinition>
|
|
79
|
+
</bpmn:intermediateCatchEvent>
|
|
80
|
+
<bpmn:endEvent id="pf_loop_end" name="Probe ready">
|
|
81
|
+
<bpmn:incoming>pf_loop_ready</bpmn:incoming>
|
|
82
|
+
</bpmn:endEvent>
|
|
83
|
+
<bpmn:sequenceFlow id="pf_loop_toProbe" sourceRef="pf_loop_start" targetRef="preflight-probe" />
|
|
84
|
+
<bpmn:sequenceFlow id="pf_loop_probed" sourceRef="preflight-probe" targetRef="pf_loop_gw" />
|
|
85
|
+
<bpmn:sequenceFlow id="pf_loop_ready" name="ready" sourceRef="pf_loop_gw" targetRef="pf_loop_end">
|
|
86
|
+
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=ready = true</bpmn:conditionExpression>
|
|
87
|
+
</bpmn:sequenceFlow>
|
|
88
|
+
<bpmn:sequenceFlow id="pf_notReady" name="not ready" sourceRef="pf_loop_gw" targetRef="pf_wait_poll" />
|
|
89
|
+
<bpmn:sequenceFlow id="pf_pollBack" sourceRef="pf_wait_poll" targetRef="preflight-probe" />
|
|
90
|
+
</bpmn:subProcess>
|
|
91
|
+
<bpmn:boundaryEvent id="be_pf_probe_timeout" name="Probe timed out" attachedToRef="preflight-probe-loop">
|
|
54
92
|
<bpmn:outgoing>pf_probeTimedOut</bpmn:outgoing>
|
|
55
93
|
<bpmn:timerEventDefinition id="ted_pf_probe_timeout">
|
|
56
94
|
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=probeTimeout</bpmn:timeDuration>
|
|
57
95
|
</bpmn:timerEventDefinition>
|
|
58
96
|
</bpmn:boundaryEvent>
|
|
97
|
+
<bpmn:serviceTask id="preflight-probe-last-attempt" name="Probe readiness (last attempt)">
|
|
98
|
+
<bpmn:extensionElements>
|
|
99
|
+
<zeebe:taskDefinition type="pr.readiness-probe" />
|
|
100
|
+
<zeebe:properties>
|
|
101
|
+
<zeebe:property name="io.nanobpm.dataEnvelope.in" value="ReadinessProbeIn" />
|
|
102
|
+
<zeebe:property name="io.nanobpm.dataEnvelope.out" value="ReadinessProbeOut" />
|
|
103
|
+
</zeebe:properties>
|
|
104
|
+
<zeebe:ioMapping>
|
|
105
|
+
<zeebe:input source="=true" target="lastAttempt" />
|
|
106
|
+
</zeebe:ioMapping>
|
|
107
|
+
</bpmn:extensionElements>
|
|
108
|
+
<bpmn:incoming>pf_probeTimedOut</bpmn:incoming>
|
|
109
|
+
<bpmn:outgoing>pf_lastAttemptDone</bpmn:outgoing>
|
|
110
|
+
</bpmn:serviceTask>
|
|
59
111
|
<bpmn:exclusiveGateway id="pf_gw" name="upstream ready?" default="pf_escalate">
|
|
60
112
|
<bpmn:incoming>pf_probed</bpmn:incoming>
|
|
61
113
|
<bpmn:outgoing>pf_ready</bpmn:outgoing>
|
|
@@ -68,7 +120,6 @@
|
|
|
68
120
|
<zeebe:assignmentDefinition candidateGroups="operators" />
|
|
69
121
|
</bpmn:extensionElements>
|
|
70
122
|
<bpmn:incoming>pf_escalate</bpmn:incoming>
|
|
71
|
-
<bpmn:incoming>pf_probeTimedOut</bpmn:incoming>
|
|
72
123
|
<bpmn:outgoing>pf_toResolution</bpmn:outgoing>
|
|
73
124
|
</bpmn:userTask>
|
|
74
125
|
<bpmn:boundaryEvent id="be_pf_sla" name="SLA elapsed" attachedToRef="readiness-escalation-pf">
|
|
@@ -88,13 +139,14 @@
|
|
|
88
139
|
<bpmn:incoming>pf_abandon</bpmn:incoming>
|
|
89
140
|
<bpmn:incoming>pf_sla</bpmn:incoming>
|
|
90
141
|
</bpmn:endEvent>
|
|
91
|
-
<bpmn:sequenceFlow id="pf_toProbe" sourceRef="pf_start" targetRef="preflight-probe" />
|
|
92
|
-
<bpmn:sequenceFlow id="pf_probed" sourceRef="preflight-probe" targetRef="pf_gw" />
|
|
142
|
+
<bpmn:sequenceFlow id="pf_toProbe" sourceRef="pf_start" targetRef="preflight-probe-loop" />
|
|
143
|
+
<bpmn:sequenceFlow id="pf_probed" sourceRef="preflight-probe-loop" targetRef="pf_gw" />
|
|
93
144
|
<bpmn:sequenceFlow id="pf_ready" name="ready" sourceRef="pf_gw" targetRef="pf_end">
|
|
94
145
|
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=ready = true</bpmn:conditionExpression>
|
|
95
146
|
</bpmn:sequenceFlow>
|
|
96
147
|
<bpmn:sequenceFlow id="pf_escalate" name="stalled" sourceRef="pf_gw" targetRef="readiness-escalation-pf" />
|
|
97
|
-
<bpmn:sequenceFlow id="pf_probeTimedOut" name="timed out" sourceRef="be_pf_probe_timeout" targetRef="
|
|
148
|
+
<bpmn:sequenceFlow id="pf_probeTimedOut" name="timed out" sourceRef="be_pf_probe_timeout" targetRef="preflight-probe-last-attempt" />
|
|
149
|
+
<bpmn:sequenceFlow id="pf_lastAttemptDone" sourceRef="preflight-probe-last-attempt" targetRef="pf_gw" />
|
|
98
150
|
<bpmn:sequenceFlow id="pf_toResolution" sourceRef="readiness-escalation-pf" targetRef="pf_gw_res" />
|
|
99
151
|
<bpmn:sequenceFlow id="pf_proceed" name="acknowledge" sourceRef="pf_gw_res" targetRef="pf_end" />
|
|
100
152
|
<bpmn:sequenceFlow id="pf_abandon" name="abandon" sourceRef="pf_gw_res" targetRef="pf_end">
|
|
@@ -473,40 +525,43 @@
|
|
|
473
525
|
<dc:Bounds x="65" y="143" width="67" height="28" />
|
|
474
526
|
</bpmndi:BPMNLabel>
|
|
475
527
|
</bpmndi:BPMNShape>
|
|
476
|
-
<bpmndi:BPMNShape id="BPMNShape_preflight-probe" bpmnElement="preflight-probe">
|
|
528
|
+
<bpmndi:BPMNShape id="BPMNShape_preflight-probe-loop" bpmnElement="preflight-probe-loop">
|
|
477
529
|
<dc:Bounds x="216" y="80" width="100" height="80" />
|
|
478
530
|
</bpmndi:BPMNShape>
|
|
531
|
+
<bpmndi:BPMNShape id="BPMNShape_preflight-probe-last-attempt" bpmnElement="preflight-probe-last-attempt">
|
|
532
|
+
<dc:Bounds x="416" y="240" width="100" height="80" />
|
|
533
|
+
</bpmndi:BPMNShape>
|
|
479
534
|
<bpmndi:BPMNShape id="BPMNShape_pf_gw" bpmnElement="pf_gw" isMarkerVisible="true">
|
|
480
|
-
<dc:Bounds x="
|
|
535
|
+
<dc:Bounds x="616" y="95" width="50" height="50" />
|
|
481
536
|
<bpmndi:BPMNLabel>
|
|
482
|
-
<dc:Bounds x="
|
|
537
|
+
<dc:Bounds x="610" y="62" width="63" height="28" />
|
|
483
538
|
</bpmndi:BPMNLabel>
|
|
484
539
|
</bpmndi:BPMNShape>
|
|
485
540
|
<bpmndi:BPMNShape id="BPMNShape_readiness-escalation-pf" bpmnElement="readiness-escalation-pf">
|
|
486
|
-
<dc:Bounds x="
|
|
541
|
+
<dc:Bounds x="766" y="80" width="100" height="80" />
|
|
487
542
|
</bpmndi:BPMNShape>
|
|
488
543
|
<bpmndi:BPMNShape id="BPMNShape_pf_gw_res" bpmnElement="pf_gw_res" isMarkerVisible="true">
|
|
489
|
-
<dc:Bounds x="
|
|
544
|
+
<dc:Bounds x="966" y="95" width="50" height="50" />
|
|
490
545
|
<bpmndi:BPMNLabel>
|
|
491
|
-
<dc:Bounds x="
|
|
546
|
+
<dc:Bounds x="951" y="76" width="81" height="14" />
|
|
492
547
|
</bpmndi:BPMNLabel>
|
|
493
548
|
</bpmndi:BPMNShape>
|
|
494
549
|
<bpmndi:BPMNShape id="BPMNShape_pf_end" bpmnElement="pf_end">
|
|
495
|
-
<dc:Bounds x="
|
|
550
|
+
<dc:Bounds x="1116" y="102" width="36" height="36" />
|
|
496
551
|
<bpmndi:BPMNLabel>
|
|
497
|
-
<dc:Bounds x="
|
|
552
|
+
<dc:Bounds x="1100" y="69" width="69" height="28" />
|
|
498
553
|
</bpmndi:BPMNLabel>
|
|
499
554
|
</bpmndi:BPMNShape>
|
|
500
555
|
<bpmndi:BPMNShape id="BPMNShape_be_pf_probe_timeout" bpmnElement="be_pf_probe_timeout">
|
|
501
556
|
<dc:Bounds x="248" y="142" width="36" height="36" />
|
|
502
557
|
<bpmndi:BPMNLabel>
|
|
503
|
-
<dc:Bounds x="
|
|
558
|
+
<dc:Bounds x="165" y="183" width="83" height="28" />
|
|
504
559
|
</bpmndi:BPMNLabel>
|
|
505
560
|
</bpmndi:BPMNShape>
|
|
506
561
|
<bpmndi:BPMNShape id="BPMNShape_be_pf_sla" bpmnElement="be_pf_sla">
|
|
507
|
-
<dc:Bounds x="
|
|
562
|
+
<dc:Bounds x="798" y="142" width="36" height="36" />
|
|
508
563
|
<bpmndi:BPMNLabel>
|
|
509
|
-
<dc:Bounds x="
|
|
564
|
+
<dc:Bounds x="774" y="223" width="84" height="14" />
|
|
510
565
|
</bpmndi:BPMNLabel>
|
|
511
566
|
</bpmndi:BPMNShape>
|
|
512
567
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_toProbe" bpmnElement="pf_toProbe">
|
|
@@ -515,63 +570,124 @@
|
|
|
515
570
|
</bpmndi:BPMNEdge>
|
|
516
571
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_probed" bpmnElement="pf_probed">
|
|
517
572
|
<di:waypoint x="316" y="120" />
|
|
518
|
-
<di:waypoint x="
|
|
573
|
+
<di:waypoint x="616" y="120" />
|
|
519
574
|
</bpmndi:BPMNEdge>
|
|
520
575
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_escalate" bpmnElement="pf_escalate">
|
|
521
|
-
<di:waypoint x="
|
|
522
|
-
<di:waypoint x="
|
|
576
|
+
<di:waypoint x="666" y="120" />
|
|
577
|
+
<di:waypoint x="766" y="120" />
|
|
523
578
|
<bpmndi:BPMNLabel>
|
|
524
|
-
<dc:Bounds x="
|
|
579
|
+
<dc:Bounds x="690" y="98" width="53" height="14" />
|
|
525
580
|
</bpmndi:BPMNLabel>
|
|
526
581
|
</bpmndi:BPMNEdge>
|
|
527
582
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_toResolution" bpmnElement="pf_toResolution">
|
|
528
|
-
<di:waypoint x="
|
|
529
|
-
<di:waypoint x="
|
|
583
|
+
<di:waypoint x="866" y="120" />
|
|
584
|
+
<di:waypoint x="966" y="120" />
|
|
530
585
|
</bpmndi:BPMNEdge>
|
|
531
586
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_proceed" bpmnElement="pf_proceed">
|
|
532
|
-
<di:waypoint x="
|
|
533
|
-
<di:waypoint x="
|
|
587
|
+
<di:waypoint x="1016" y="120" />
|
|
588
|
+
<di:waypoint x="1116" y="120" />
|
|
534
589
|
<bpmndi:BPMNLabel>
|
|
535
|
-
<dc:Bounds x="
|
|
590
|
+
<dc:Bounds x="1024" y="128" width="84" height="14" />
|
|
536
591
|
</bpmndi:BPMNLabel>
|
|
537
592
|
</bpmndi:BPMNEdge>
|
|
538
593
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_ready" bpmnElement="pf_ready">
|
|
539
|
-
<di:waypoint x="
|
|
540
|
-
<di:waypoint x="
|
|
541
|
-
<di:waypoint x="
|
|
542
|
-
<di:waypoint x="
|
|
594
|
+
<di:waypoint x="641" y="145" />
|
|
595
|
+
<di:waypoint x="641" y="200" />
|
|
596
|
+
<di:waypoint x="1134" y="200" />
|
|
597
|
+
<di:waypoint x="1134" y="138" />
|
|
543
598
|
<bpmndi:BPMNLabel>
|
|
544
|
-
<dc:Bounds x="
|
|
599
|
+
<dc:Bounds x="868" y="178" width="39" height="14" />
|
|
545
600
|
</bpmndi:BPMNLabel>
|
|
546
601
|
</bpmndi:BPMNEdge>
|
|
602
|
+
<bpmndi:BPMNEdge id="BPMNEdge_pf_lastAttemptDone" bpmnElement="pf_lastAttemptDone">
|
|
603
|
+
<di:waypoint x="466" y="240" />
|
|
604
|
+
<di:waypoint x="466" y="120" />
|
|
605
|
+
<di:waypoint x="616" y="120" />
|
|
606
|
+
</bpmndi:BPMNEdge>
|
|
547
607
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_abandon" bpmnElement="pf_abandon">
|
|
548
|
-
<di:waypoint x="
|
|
549
|
-
<di:waypoint x="
|
|
608
|
+
<di:waypoint x="1016" y="120" />
|
|
609
|
+
<di:waypoint x="1116" y="120" />
|
|
550
610
|
<bpmndi:BPMNLabel>
|
|
551
|
-
<dc:Bounds x="
|
|
611
|
+
<dc:Bounds x="1040" y="158" width="53" height="14" />
|
|
552
612
|
</bpmndi:BPMNLabel>
|
|
553
613
|
</bpmndi:BPMNEdge>
|
|
554
614
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_probeTimedOut" bpmnElement="pf_probeTimedOut">
|
|
555
615
|
<di:waypoint x="266" y="178" />
|
|
556
|
-
<di:waypoint x="266" y="
|
|
557
|
-
<di:waypoint x="
|
|
558
|
-
<di:waypoint x="336" y="82" />
|
|
559
|
-
<di:waypoint x="546" y="82" />
|
|
560
|
-
<di:waypoint x="546" y="120" />
|
|
561
|
-
<di:waypoint x="566" y="120" />
|
|
616
|
+
<di:waypoint x="266" y="280" />
|
|
617
|
+
<di:waypoint x="416" y="280" />
|
|
562
618
|
<bpmndi:BPMNLabel>
|
|
563
|
-
<dc:Bounds x="
|
|
619
|
+
<dc:Bounds x="271" y="222" width="67" height="14" />
|
|
564
620
|
</bpmndi:BPMNLabel>
|
|
565
621
|
</bpmndi:BPMNEdge>
|
|
566
622
|
<bpmndi:BPMNEdge id="BPMNEdge_pf_sla" bpmnElement="pf_sla">
|
|
567
|
-
<di:waypoint x="
|
|
568
|
-
<di:waypoint x="
|
|
569
|
-
<di:waypoint x="
|
|
570
|
-
<di:waypoint x="
|
|
623
|
+
<di:waypoint x="816" y="178" />
|
|
624
|
+
<di:waypoint x="816" y="198" />
|
|
625
|
+
<di:waypoint x="1134" y="198" />
|
|
626
|
+
<di:waypoint x="1134" y="138" />
|
|
627
|
+
<bpmndi:BPMNLabel>
|
|
628
|
+
<dc:Bounds x="931" y="165" width="88" height="28" />
|
|
629
|
+
</bpmndi:BPMNLabel>
|
|
630
|
+
</bpmndi:BPMNEdge>
|
|
631
|
+
</bpmndi:BPMNPlane>
|
|
632
|
+
</bpmndi:BPMNDiagram>
|
|
633
|
+
<bpmndi:BPMNDiagram id="BPMNDiagram_preflight-probe-loop">
|
|
634
|
+
<bpmndi:BPMNPlane id="BPMNPlane_preflight-probe-loop" bpmnElement="preflight-probe-loop">
|
|
635
|
+
<bpmndi:BPMNShape id="BPMNShape_pf_loop_start" bpmnElement="pf_loop_start">
|
|
636
|
+
<dc:Bounds x="80" y="102" width="36" height="36" />
|
|
637
|
+
<bpmndi:BPMNLabel>
|
|
638
|
+
<dc:Bounds x="58" y="143" width="80" height="28" />
|
|
639
|
+
</bpmndi:BPMNLabel>
|
|
640
|
+
</bpmndi:BPMNShape>
|
|
641
|
+
<bpmndi:BPMNShape id="BPMNShape_preflight-probe" bpmnElement="preflight-probe">
|
|
642
|
+
<dc:Bounds x="216" y="80" width="100" height="80" />
|
|
643
|
+
</bpmndi:BPMNShape>
|
|
644
|
+
<bpmndi:BPMNShape id="BPMNShape_pf_loop_gw" bpmnElement="pf_loop_gw" isMarkerVisible="true">
|
|
645
|
+
<dc:Bounds x="416" y="95" width="50" height="50" />
|
|
646
|
+
<bpmndi:BPMNLabel>
|
|
647
|
+
<dc:Bounds x="418" y="76" width="46" height="14" />
|
|
648
|
+
</bpmndi:BPMNLabel>
|
|
649
|
+
</bpmndi:BPMNShape>
|
|
650
|
+
<bpmndi:BPMNShape id="BPMNShape_pf_wait_poll" bpmnElement="pf_wait_poll">
|
|
651
|
+
<dc:Bounds x="566" y="262" width="36" height="36" />
|
|
652
|
+
<bpmndi:BPMNLabel>
|
|
653
|
+
<dc:Bounds x="550" y="229" width="68" height="28" />
|
|
654
|
+
</bpmndi:BPMNLabel>
|
|
655
|
+
</bpmndi:BPMNShape>
|
|
656
|
+
<bpmndi:BPMNShape id="BPMNShape_pf_loop_end" bpmnElement="pf_loop_end">
|
|
657
|
+
<dc:Bounds x="566" y="102" width="36" height="36" />
|
|
658
|
+
<bpmndi:BPMNLabel>
|
|
659
|
+
<dc:Bounds x="544" y="143" width="80" height="14" />
|
|
660
|
+
</bpmndi:BPMNLabel>
|
|
661
|
+
</bpmndi:BPMNShape>
|
|
662
|
+
<bpmndi:BPMNEdge id="BPMNEdge_pf_loop_toProbe" bpmnElement="pf_loop_toProbe">
|
|
663
|
+
<di:waypoint x="116" y="120" />
|
|
664
|
+
<di:waypoint x="216" y="120" />
|
|
665
|
+
</bpmndi:BPMNEdge>
|
|
666
|
+
<bpmndi:BPMNEdge id="BPMNEdge_pf_loop_probed" bpmnElement="pf_loop_probed">
|
|
667
|
+
<di:waypoint x="316" y="120" />
|
|
668
|
+
<di:waypoint x="416" y="120" />
|
|
669
|
+
</bpmndi:BPMNEdge>
|
|
670
|
+
<bpmndi:BPMNEdge id="BPMNEdge_pf_loop_ready" bpmnElement="pf_loop_ready">
|
|
671
|
+
<di:waypoint x="466" y="120" />
|
|
672
|
+
<di:waypoint x="566" y="120" />
|
|
571
673
|
<bpmndi:BPMNLabel>
|
|
572
|
-
<dc:Bounds x="
|
|
674
|
+
<dc:Bounds x="497" y="98" width="39" height="14" />
|
|
573
675
|
</bpmndi:BPMNLabel>
|
|
574
676
|
</bpmndi:BPMNEdge>
|
|
677
|
+
<bpmndi:BPMNEdge id="BPMNEdge_pf_notReady" bpmnElement="pf_notReady">
|
|
678
|
+
<di:waypoint x="441" y="145" />
|
|
679
|
+
<di:waypoint x="441" y="280" />
|
|
680
|
+
<di:waypoint x="566" y="280" />
|
|
681
|
+
<bpmndi:BPMNLabel>
|
|
682
|
+
<dc:Bounds x="446" y="206" width="64" height="14" />
|
|
683
|
+
</bpmndi:BPMNLabel>
|
|
684
|
+
</bpmndi:BPMNEdge>
|
|
685
|
+
<bpmndi:BPMNEdge id="BPMNEdge_pf_pollBack" bpmnElement="pf_pollBack">
|
|
686
|
+
<di:waypoint x="584" y="298" />
|
|
687
|
+
<di:waypoint x="584" y="318" />
|
|
688
|
+
<di:waypoint x="266" y="318" />
|
|
689
|
+
<di:waypoint x="266" y="160" />
|
|
690
|
+
</bpmndi:BPMNEdge>
|
|
575
691
|
</bpmndi:BPMNPlane>
|
|
576
692
|
</bpmndi:BPMNDiagram>
|
|
577
693
|
</bpmn:definitions>
|