@temporal-architect/claude-plugin 0.9.0
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/LICENSE +21 -0
- package/README.md +38 -0
- package/package.json +37 -0
- package/skills/MANIFEST.json +373 -0
- package/skills/MANIFEST.md +121 -0
- package/skills/temporal-architect/SKILL.md +99 -0
- package/skills/temporal-architect/reference/decomposition.md +78 -0
- package/skills/temporal-architect-author-go/README.md +16 -0
- package/skills/temporal-architect-author-go/SKILL.md +191 -0
- package/skills/temporal-architect-author-go/SUBAGENT_ADOPTION.md +161 -0
- package/skills/temporal-architect-author-go/reference/activity-call.md +73 -0
- package/skills/temporal-architect-author-go/reference/activity-def.md +54 -0
- package/skills/temporal-architect-author-go/reference/assignment.md +36 -0
- package/skills/temporal-architect-author-go/reference/await-all.md +104 -0
- package/skills/temporal-architect-author-go/reference/await-one.md +193 -0
- package/skills/temporal-architect-author-go/reference/await-timer.md +35 -0
- package/skills/temporal-architect-author-go/reference/close.md +71 -0
- package/skills/temporal-architect-author-go/reference/composite-patterns.md +176 -0
- package/skills/temporal-architect-author-go/reference/condition.md +56 -0
- package/skills/temporal-architect-author-go/reference/control-flow.md +151 -0
- package/skills/temporal-architect-author-go/reference/dependency-resolution.md +29 -0
- package/skills/temporal-architect-author-go/reference/detach.md +52 -0
- package/skills/temporal-architect-author-go/reference/heartbeat.md +84 -0
- package/skills/temporal-architect-author-go/reference/nexus-service-def.md +73 -0
- package/skills/temporal-architect-author-go/reference/nexus.md +35 -0
- package/skills/temporal-architect-author-go/reference/options.md +138 -0
- package/skills/temporal-architect-author-go/reference/promise.md +73 -0
- package/skills/temporal-architect-author-go/reference/proto-driven.md +197 -0
- package/skills/temporal-architect-author-go/reference/query-handler.md +34 -0
- package/skills/temporal-architect-author-go/reference/signal-handler.md +73 -0
- package/skills/temporal-architect-author-go/reference/three-layer-testing.md +173 -0
- package/skills/temporal-architect-author-go/reference/types.md +72 -0
- package/skills/temporal-architect-author-go/reference/update-handler.md +64 -0
- package/skills/temporal-architect-author-go/reference/worker.md +215 -0
- package/skills/temporal-architect-author-go/reference/workflow-call.md +37 -0
- package/skills/temporal-architect-author-go/reference/workflow-def.md +45 -0
- package/skills/temporal-architect-author-infra/README.md +16 -0
- package/skills/temporal-architect-author-infra/SKILL.md +132 -0
- package/skills/temporal-architect-author-infra/reference/tcld.md +112 -0
- package/skills/temporal-architect-author-infra/reference/terraform.md +125 -0
- package/skills/temporal-architect-design/README.md +16 -0
- package/skills/temporal-architect-design/SKILL.md +224 -0
- package/skills/temporal-architect-design/reference/LANGUAGE.md +5 -0
- package/skills/temporal-architect-design/reference/anti-patterns.md +332 -0
- package/skills/temporal-architect-design/reference/common-errors.md +88 -0
- package/skills/temporal-architect-design/reference/core-principles.md +52 -0
- package/skills/temporal-architect-design/reference/design-checklist.md +59 -0
- package/skills/temporal-architect-design/reference/namespaces.md +84 -0
- package/skills/temporal-architect-design/reference/notation-examples.md +304 -0
- package/skills/temporal-architect-design/reference/notation-reference.md +70 -0
- package/skills/temporal-architect-design/reference/primitives-reference.md +65 -0
- package/skills/temporal-architect-design/reference/project-discovery-subagent.md +80 -0
- package/skills/temporal-architect-design/reference/reverse-engineering.md +53 -0
- package/skills/temporal-architect-design/reference/twf-conventions.md +43 -0
- package/skills/temporal-architect-design/reference/workflow-boundaries.md +43 -0
- package/skills/temporal-architect-design/topics/activities-advanced.md +358 -0
- package/skills/temporal-architect-design/topics/activities-advanced.twf +107 -0
- package/skills/temporal-architect-design/topics/child-workflows.md +347 -0
- package/skills/temporal-architect-design/topics/child-workflows.twf +171 -0
- package/skills/temporal-architect-design/topics/long-running.md +230 -0
- package/skills/temporal-architect-design/topics/long-running.twf +100 -0
- package/skills/temporal-architect-design/topics/nexus.md +248 -0
- package/skills/temporal-architect-design/topics/nexus.twf +148 -0
- package/skills/temporal-architect-design/topics/patterns.md +469 -0
- package/skills/temporal-architect-design/topics/patterns.twf +346 -0
- package/skills/temporal-architect-design/topics/promises-conditions.md +179 -0
- package/skills/temporal-architect-design/topics/promises-conditions.twf +213 -0
- package/skills/temporal-architect-design/topics/signals-queries-updates.md +319 -0
- package/skills/temporal-architect-design/topics/signals-queries-updates.twf +234 -0
- package/skills/temporal-architect-design/topics/task-queues.md +205 -0
- package/skills/temporal-architect-design/topics/task-queues.twf +184 -0
- package/skills/temporal-architect-design/topics/testing.md +437 -0
- package/skills/temporal-architect-design/topics/testing.twf +177 -0
- package/skills/temporal-architect-design/topics/timers-scheduling.md +131 -0
- package/skills/temporal-architect-design/topics/timers-scheduling.twf +129 -0
- package/skills/temporal-architect-design/topics/versioning.md +434 -0
- package/skills/temporal-architect-design/topics/versioning.twf +174 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# Child Workflows
|
|
2
|
+
|
|
3
|
+
> **Example:** [`child-workflows.twf`](./child-workflows.twf)
|
|
4
|
+
|
|
5
|
+
Nested workflow execution for decomposition, reusability, and independent failure boundaries.
|
|
6
|
+
|
|
7
|
+
## When to Use Child Workflows
|
|
8
|
+
|
|
9
|
+
| Use Child Workflow | Use Activity Instead |
|
|
10
|
+
|--------------------|---------------------|
|
|
11
|
+
| Multi-step operation with own retry logic | Single atomic operation |
|
|
12
|
+
| Reusable across multiple parent workflows | One-off operation |
|
|
13
|
+
| Need independent timeout/retry policies | Same policies as parent |
|
|
14
|
+
| Operation is complex enough to warrant own tests | Simple request-response |
|
|
15
|
+
| Very long operation (separate history) | Completes quickly |
|
|
16
|
+
| Different failure semantics needed | Parent handles all failures |
|
|
17
|
+
|
|
18
|
+
**Rule of thumb:** If the operation has its own "shape" that you'd want to test independently, it's a child workflow.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Basic Pattern
|
|
23
|
+
|
|
24
|
+
```twf
|
|
25
|
+
workflow ParentWorkflow(input: Input) -> (Result):
|
|
26
|
+
# Simple child workflow call
|
|
27
|
+
workflow ChildWorkflow(input.data) -> childResult
|
|
28
|
+
|
|
29
|
+
# Child workflow with options
|
|
30
|
+
workflow ChildWorkflow(input.data) -> childResult
|
|
31
|
+
options:
|
|
32
|
+
workflow_execution_timeout: 1h
|
|
33
|
+
retry_policy:
|
|
34
|
+
maximum_attempts: 3
|
|
35
|
+
|
|
36
|
+
close complete(Result{childResult})
|
|
37
|
+
|
|
38
|
+
workflow ChildWorkflow(data: Data) -> (ChildResult):
|
|
39
|
+
activity Step1(data)
|
|
40
|
+
activity Step2(data)
|
|
41
|
+
close complete(ChildResult{success: true})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Execution Modes: `workflow`, `promise`, `detach`
|
|
47
|
+
|
|
48
|
+
Child workflows support three execution modes:
|
|
49
|
+
|
|
50
|
+
| Mode | Syntax | Behavior | Result |
|
|
51
|
+
|------|--------|----------|--------|
|
|
52
|
+
| **Synchronous** | `workflow Name(args) -> result` | Parent blocks until child completes | Child result bound to variable |
|
|
53
|
+
| **Async (promise)** | `promise p <- workflow Name(args)` | Parent continues immediately | Promise for later awaiting |
|
|
54
|
+
| **Fire-and-forget (detach)** | `detach workflow Name(args)` | Parent continues, never waits | No result binding |
|
|
55
|
+
|
|
56
|
+
### Synchronous (Default)
|
|
57
|
+
|
|
58
|
+
Parent blocks until child workflow completes and receives the result:
|
|
59
|
+
|
|
60
|
+
```twf
|
|
61
|
+
workflow Parent(input: Input) -> (Result):
|
|
62
|
+
workflow ChildWorkflow(input.data) -> childResult
|
|
63
|
+
close complete(Result{childResult})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Async with `promise`
|
|
67
|
+
|
|
68
|
+
Start a child workflow and get a promise. Continue with other work, then await the promise later:
|
|
69
|
+
|
|
70
|
+
```twf
|
|
71
|
+
workflow Parent(input: Input) -> (Result):
|
|
72
|
+
# Start child without blocking
|
|
73
|
+
promise handle <- workflow SlowChild(input.data)
|
|
74
|
+
|
|
75
|
+
# Do other work in parallel
|
|
76
|
+
activity QuickTask(input)
|
|
77
|
+
|
|
78
|
+
# Await child result when needed
|
|
79
|
+
await handle -> childResult
|
|
80
|
+
|
|
81
|
+
close complete(Result{childResult})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Fire-and-forget with `detach`
|
|
85
|
+
|
|
86
|
+
Start a child workflow that runs independently. The parent never waits for it and cannot receive its result. Detached children survive parent completion, cancellation, or failure.
|
|
87
|
+
|
|
88
|
+
```twf
|
|
89
|
+
workflow Parent(input: Input) -> (Result):
|
|
90
|
+
activity ProcessOrder(input) -> result
|
|
91
|
+
|
|
92
|
+
# Fire-and-forget notification - runs independently
|
|
93
|
+
detach workflow SendNotification(input.customer, result)
|
|
94
|
+
|
|
95
|
+
close complete(Result{result})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
> **Note:** `detach` implies `ABANDON` parent close policy. The detached child continues even if the parent is cancelled or terminated.
|
|
99
|
+
|
|
100
|
+
### `promise` and `detach` with Nexus
|
|
101
|
+
|
|
102
|
+
Both modifiers also work with nexus calls for cross-namespace workflows:
|
|
103
|
+
|
|
104
|
+
```twf
|
|
105
|
+
nexus service PaymentsService:
|
|
106
|
+
async ProcessPayment workflow ProcessPayment
|
|
107
|
+
|
|
108
|
+
nexus service NotificationsService:
|
|
109
|
+
async SendEmail workflow SendEmail
|
|
110
|
+
|
|
111
|
+
workflow Parent(input: Input) -> (Result):
|
|
112
|
+
# Async nexus call
|
|
113
|
+
promise handle <- nexus PaymentsEndpoint PaymentsService.ProcessPayment(input.payment)
|
|
114
|
+
|
|
115
|
+
# Fire-and-forget nexus call
|
|
116
|
+
detach nexus NotificationsEndpoint NotificationsService.SendEmail(input.customer)
|
|
117
|
+
|
|
118
|
+
# Await the async promise
|
|
119
|
+
await handle -> paymentResult
|
|
120
|
+
|
|
121
|
+
close complete(Result{paymentResult})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Parent-Child Lifecycle
|
|
127
|
+
|
|
128
|
+
### Execution Relationship
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
Parent starts
|
|
132
|
+
├─ Child starts
|
|
133
|
+
│ ├─ Child activities execute
|
|
134
|
+
│ └─ Child completes/fails
|
|
135
|
+
└─ Parent continues with child result
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Cancellation Propagation
|
|
139
|
+
|
|
140
|
+
Child behavior at parent close is governed by `parent_close_policy`. The default is `TERMINATE`, which **terminates** the child (not merely cancels it) when the parent closes — "parent closes" is broader than "parent cancelled," and the distinction matters. Use `detach` (which implies `ABANDON`) for fire-and-forget children that survive parent close.
|
|
141
|
+
|
|
142
|
+
> **Interaction with `await one`:** if a child workflow is one branch of an `await one` race and a *different* branch wins, the child is **not** cancelled by losing the race — it continues running. What ultimately happens to it is decided by its `parent_close_policy` when the parent closes (terminate by default, abandon if detached). Racing a child against a timeout does not stop the child; rely on `parent_close_policy`, or compensate explicitly.
|
|
143
|
+
|
|
144
|
+
```twf
|
|
145
|
+
workflow Parent(input: Input) -> (Result):
|
|
146
|
+
# Default: child cancelled if parent cancelled
|
|
147
|
+
workflow ChildWorkflow(input)
|
|
148
|
+
|
|
149
|
+
# Detached: child continues even if parent cancelled
|
|
150
|
+
detach workflow ChildWorkflow(input)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Parent Close Policies
|
|
154
|
+
|
|
155
|
+
| Policy | Behavior |
|
|
156
|
+
|--------|----------|
|
|
157
|
+
| `TERMINATE` | Child terminated when parent closes (default) |
|
|
158
|
+
| `ABANDON` | Child continues running independently |
|
|
159
|
+
| `REQUEST_CANCEL` | Cancellation requested but child can handle gracefully |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Error Handling
|
|
164
|
+
|
|
165
|
+
### Child Failure Modes
|
|
166
|
+
|
|
167
|
+
> Note: Error handling is SDK-specific. The workflow will fail if a child workflow fails (after retries). Use retry policies and timeouts to control failure behavior.
|
|
168
|
+
|
|
169
|
+
```twf
|
|
170
|
+
workflow Parent(input: Input) -> (Result):
|
|
171
|
+
# Child workflow call -- if it fails, the parent workflow fails
|
|
172
|
+
workflow ChildWorkflow(input) -> result
|
|
173
|
+
close complete(Result{success: true, data: result})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Retry Policies for Children
|
|
177
|
+
|
|
178
|
+
```twf
|
|
179
|
+
workflow Parent(input: Input) -> (Result):
|
|
180
|
+
# Child with custom retry policy
|
|
181
|
+
workflow ProcessOrder(input.order)
|
|
182
|
+
options:
|
|
183
|
+
retry_policy:
|
|
184
|
+
initial_interval: 1s
|
|
185
|
+
backoff_coefficient: 2.0
|
|
186
|
+
maximum_interval: 60s
|
|
187
|
+
maximum_attempts: 5
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Workflow ID Design
|
|
193
|
+
|
|
194
|
+
Child workflow IDs determine uniqueness and idempotency. Workflow ID assignment and reuse policies are SDK-level concerns and are not expressed in the TWF DSL. When implementing your workflows, use the SDK to set `workflow_id` and `workflow_id_reuse_policy` on child workflow stubs.
|
|
195
|
+
|
|
196
|
+
### Common Patterns (SDK-level)
|
|
197
|
+
|
|
198
|
+
- **Derived from parent + child identifier:** `"{parent_id}-child-{item.id}"`
|
|
199
|
+
- **Deterministic from business entity:** `"order-{order.id}"`
|
|
200
|
+
- **With attempt counter for retries:** `"op-{data.id}-attempt-{attemptCount}"`
|
|
201
|
+
|
|
202
|
+
### Idempotency via Workflow ID
|
|
203
|
+
|
|
204
|
+
Using a deterministic workflow ID ensures idempotency: if a child with the same ID already exists and completed, the SDK returns the cached result. Configure this through workflow ID reuse policies in your SDK code.
|
|
205
|
+
|
|
206
|
+
### Workflow ID Reuse Policies (SDK-level)
|
|
207
|
+
|
|
208
|
+
| Policy | Behavior |
|
|
209
|
+
|--------|----------|
|
|
210
|
+
| `ALLOW_DUPLICATE` | Start new execution even if ID exists |
|
|
211
|
+
| `ALLOW_DUPLICATE_FAILED_ONLY` | New execution only if previous failed |
|
|
212
|
+
| `REJECT_DUPLICATE` | Error if workflow ID already exists |
|
|
213
|
+
| `TERMINATE_IF_RUNNING` | Terminate existing, start new |
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Decomposition Patterns
|
|
218
|
+
|
|
219
|
+
### Sequential Sub-Operations
|
|
220
|
+
|
|
221
|
+
```twf
|
|
222
|
+
workflow DeployApplication(app: App) -> (DeployResult):
|
|
223
|
+
# Each child has own failure boundary
|
|
224
|
+
workflow DeployDatabase(app.database)
|
|
225
|
+
workflow DeployBackend(app.backend)
|
|
226
|
+
workflow DeployFrontend(app.frontend)
|
|
227
|
+
workflow ConfigureRouting(app)
|
|
228
|
+
|
|
229
|
+
close complete(DeployResult{status: "deployed"})
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Parallel Children
|
|
233
|
+
|
|
234
|
+
```twf
|
|
235
|
+
workflow ParallelItemBatch(items: []Item) -> (BatchResult):
|
|
236
|
+
# Start all children in parallel
|
|
237
|
+
await all:
|
|
238
|
+
for (item in items):
|
|
239
|
+
workflow ProcessItem(item) -> result
|
|
240
|
+
|
|
241
|
+
close complete(BatchResult{})
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Conditional Children
|
|
245
|
+
|
|
246
|
+
```twf
|
|
247
|
+
workflow Onboarding(user: User) -> (OnboardingResult):
|
|
248
|
+
workflow CreateAccount(user)
|
|
249
|
+
|
|
250
|
+
if user.type == "enterprise":
|
|
251
|
+
workflow EnterpriseSetup(user)
|
|
252
|
+
else:
|
|
253
|
+
workflow StandardSetup(user)
|
|
254
|
+
|
|
255
|
+
workflow SendWelcomeEmail(user)
|
|
256
|
+
close complete(OnboardingResult{success: true})
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Hierarchical Decomposition
|
|
260
|
+
|
|
261
|
+
```text
|
|
262
|
+
workflow DeployShard(shard: Shard) -> ShardResult:
|
|
263
|
+
# Level 1: Shard deployment
|
|
264
|
+
├─ workflow DeployOrganization(shard.org1)
|
|
265
|
+
│ # Level 2: Org deployment
|
|
266
|
+
│ ├─ workflow DeployPeer(org1.peer1)
|
|
267
|
+
│ │ # Level 3: Component deployment
|
|
268
|
+
│ │ ├─ activity CreateCertificates(peer1)
|
|
269
|
+
│ │ ├─ activity DeployContainer(peer1)
|
|
270
|
+
│ │ └─ activity ConfigureNetwork(peer1)
|
|
271
|
+
│ └─ workflow DeployPeer(org1.peer2)
|
|
272
|
+
└─ workflow DeployOrganization(shard.org2)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Testing Child Workflows
|
|
278
|
+
|
|
279
|
+
### Unit Testing Parent
|
|
280
|
+
|
|
281
|
+
Mock child workflows to test parent orchestration logic:
|
|
282
|
+
|
|
283
|
+
> Note: Test examples use conceptual test framework pseudo-code, not TWF notation.
|
|
284
|
+
|
|
285
|
+
```pseudo
|
|
286
|
+
test "parent calls children in correct order":
|
|
287
|
+
mock ChildA -> {result: "a"}
|
|
288
|
+
mock ChildB -> {result: "b"}
|
|
289
|
+
|
|
290
|
+
result = execute Parent(input)
|
|
291
|
+
|
|
292
|
+
assert ChildA called with (input.dataA)
|
|
293
|
+
assert ChildB called with (input.dataB)
|
|
294
|
+
assert ChildB called after ChildA
|
|
295
|
+
assert result == {a: "a", b: "b"}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Integration Testing
|
|
299
|
+
|
|
300
|
+
Test parent and children together:
|
|
301
|
+
|
|
302
|
+
```pseudo
|
|
303
|
+
test "full workflow execution":
|
|
304
|
+
# Real child workflow implementations
|
|
305
|
+
result = execute Parent(input)
|
|
306
|
+
|
|
307
|
+
assert result.status == "success"
|
|
308
|
+
assert external_system.has(expected_state)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Anti-Patterns
|
|
314
|
+
|
|
315
|
+
### Too Many Children
|
|
316
|
+
|
|
317
|
+
```twf
|
|
318
|
+
# BAD: Every operation is a child workflow
|
|
319
|
+
workflow Parent(data: Data):
|
|
320
|
+
workflow Step1(data) # Just calls one activity
|
|
321
|
+
workflow Step2(data) # Just calls one activity
|
|
322
|
+
workflow Step3(data) # Just calls one activity
|
|
323
|
+
|
|
324
|
+
# GOOD: Children for meaningful decomposition
|
|
325
|
+
workflow Parent(data: Data):
|
|
326
|
+
activity Step1(data)
|
|
327
|
+
activity Step2(data)
|
|
328
|
+
workflow ComplexOperation(data) # Has multiple steps, own retry logic
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Ignoring Child Failures
|
|
332
|
+
|
|
333
|
+
> Note: Error handling is SDK-specific. This example uses conceptual pseudo-code.
|
|
334
|
+
|
|
335
|
+
```twf
|
|
336
|
+
# BAD: Silent failure (SDK-level: catching and ignoring child errors)
|
|
337
|
+
# GOOD: Track failures and alert
|
|
338
|
+
workflow Parent(items: []Item):
|
|
339
|
+
for (item in items):
|
|
340
|
+
workflow ProcessItem(item)
|
|
341
|
+
# SDK-level: collect results, alert on partial failures
|
|
342
|
+
activity AlertOnPartialFailure(items)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Hardcoded Workflow IDs (SDK-level)
|
|
346
|
+
|
|
347
|
+
When setting workflow IDs in your SDK code, always derive them from business entities to avoid collisions. Using a static workflow ID like `"process-order"` for all orders causes failures; use `"process-order-{order.id}"` instead.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Source: child-workflows.md
|
|
2
|
+
# Patterns: sequential/parallel/conditional children, detached, workflow ID
|
|
3
|
+
|
|
4
|
+
# --- Basic parent-child ---
|
|
5
|
+
|
|
6
|
+
workflow ParentWorkflow(input: Input) -> (Result):
|
|
7
|
+
# Simple child workflow call
|
|
8
|
+
workflow ChildWorkflow(input.data) -> childResult
|
|
9
|
+
|
|
10
|
+
# Child with options
|
|
11
|
+
workflow ChildWorkflow(input.data) -> childResult2
|
|
12
|
+
options:
|
|
13
|
+
workflow_execution_timeout: 1h
|
|
14
|
+
retry_policy:
|
|
15
|
+
maximum_attempts: 3
|
|
16
|
+
|
|
17
|
+
close complete(Result{childResult, childResult2})
|
|
18
|
+
|
|
19
|
+
workflow ChildWorkflow(data: Data) -> (ChildResult):
|
|
20
|
+
activity ValidateInput(data)
|
|
21
|
+
activity TransformData(data)
|
|
22
|
+
close complete(ChildResult{success: true})
|
|
23
|
+
|
|
24
|
+
# --- Sequential decomposition ---
|
|
25
|
+
|
|
26
|
+
workflow DeployApplication(app: App) -> (DeployResult):
|
|
27
|
+
# Each child has own failure boundary
|
|
28
|
+
workflow DeployInfrastructure(app) -> infraResult
|
|
29
|
+
workflow DeployServices(app) -> servicesResult
|
|
30
|
+
|
|
31
|
+
close complete(DeployResult{status: "deployed"})
|
|
32
|
+
|
|
33
|
+
workflow DeployInfrastructure(app: App) -> (DeployResult):
|
|
34
|
+
activity ProvisionDatabase(app.database)
|
|
35
|
+
activity RunMigrations(app.database)
|
|
36
|
+
close complete(DeployResult{status: "done"})
|
|
37
|
+
|
|
38
|
+
workflow DeployServices(app: App) -> (DeployResult):
|
|
39
|
+
activity BuildArtifacts(app)
|
|
40
|
+
activity DeployContainers(app)
|
|
41
|
+
close complete(DeployResult{status: "done"})
|
|
42
|
+
|
|
43
|
+
# --- Parallel children ---
|
|
44
|
+
|
|
45
|
+
workflow ParallelItemBatch(items: []Item) -> (BatchResult):
|
|
46
|
+
await all:
|
|
47
|
+
for (item in items):
|
|
48
|
+
workflow ProcessItem(item)
|
|
49
|
+
|
|
50
|
+
close complete(BatchResult{})
|
|
51
|
+
|
|
52
|
+
workflow ProcessItem(item: Item) -> (ItemResult):
|
|
53
|
+
activity ProcessSingleItem(item) -> result
|
|
54
|
+
close complete(ItemResult{result})
|
|
55
|
+
|
|
56
|
+
# --- Conditional children ---
|
|
57
|
+
|
|
58
|
+
workflow Onboarding(user: User) -> (OnboardingResult):
|
|
59
|
+
workflow CreateAccount(user) -> accountResult
|
|
60
|
+
|
|
61
|
+
if (user.type == "enterprise"):
|
|
62
|
+
workflow EnterpriseSetup(user) -> setupResult
|
|
63
|
+
else:
|
|
64
|
+
workflow StandardSetup(user) -> setupResult
|
|
65
|
+
|
|
66
|
+
workflow SendWelcomeEmail(user) -> emailResult
|
|
67
|
+
close complete(OnboardingResult{success: true})
|
|
68
|
+
|
|
69
|
+
workflow CreateAccount(user: User) -> (AccountResult):
|
|
70
|
+
activity CreateUserRecord(user)
|
|
71
|
+
close complete(AccountResult{success: true})
|
|
72
|
+
|
|
73
|
+
workflow EnterpriseSetup(user: User) -> (SetupResult):
|
|
74
|
+
activity ConfigureEnterprise(user)
|
|
75
|
+
close complete(SetupResult{done: true})
|
|
76
|
+
|
|
77
|
+
workflow StandardSetup(user: User) -> (SetupResult):
|
|
78
|
+
activity ConfigureStandard(user)
|
|
79
|
+
close complete(SetupResult{done: true})
|
|
80
|
+
|
|
81
|
+
workflow SendWelcomeEmail(user: User) -> (EmailResult):
|
|
82
|
+
activity SendEmail(user.email, "Welcome!")
|
|
83
|
+
close complete(EmailResult{sent: true})
|
|
84
|
+
|
|
85
|
+
# --- Detached child (fire-and-forget) ---
|
|
86
|
+
|
|
87
|
+
workflow ParentWithDetach(order: Order) -> (OrderResult):
|
|
88
|
+
activity ProcessOrder(order) -> result
|
|
89
|
+
# Fire-and-forget notification
|
|
90
|
+
detach workflow NotifyCustomer(order.customer)
|
|
91
|
+
close complete(OrderResult{status: "done"})
|
|
92
|
+
|
|
93
|
+
workflow NotifyCustomer(customer: Customer):
|
|
94
|
+
activity SendCustomerNotification(customer)
|
|
95
|
+
|
|
96
|
+
# --- Supporting activities ---
|
|
97
|
+
|
|
98
|
+
activity ValidateInput(data: Data):
|
|
99
|
+
validate(data)
|
|
100
|
+
|
|
101
|
+
activity TransformData(data: Data):
|
|
102
|
+
transform(data)
|
|
103
|
+
|
|
104
|
+
activity ProvisionDatabase(database: Database):
|
|
105
|
+
provision(database)
|
|
106
|
+
|
|
107
|
+
activity RunMigrations(database: Database):
|
|
108
|
+
migrate(database)
|
|
109
|
+
|
|
110
|
+
activity BuildArtifacts(app: App):
|
|
111
|
+
build(app)
|
|
112
|
+
|
|
113
|
+
activity DeployContainers(app: App):
|
|
114
|
+
deploy(app)
|
|
115
|
+
|
|
116
|
+
activity ProcessSingleItem(item: Item) -> (Result):
|
|
117
|
+
return process(item)
|
|
118
|
+
|
|
119
|
+
activity CreateUserRecord(user: User):
|
|
120
|
+
db.insert(user)
|
|
121
|
+
|
|
122
|
+
activity ConfigureEnterprise(user: User):
|
|
123
|
+
setup_enterprise(user)
|
|
124
|
+
|
|
125
|
+
activity ConfigureStandard(user: User):
|
|
126
|
+
setup_standard(user)
|
|
127
|
+
|
|
128
|
+
activity SendEmail(email: string, message: string):
|
|
129
|
+
send(email, message)
|
|
130
|
+
|
|
131
|
+
activity ProcessOrder(order: Order) -> (OrderResult):
|
|
132
|
+
return process(order)
|
|
133
|
+
|
|
134
|
+
activity SendCustomerNotification(customer: Customer):
|
|
135
|
+
notify(customer)
|
|
136
|
+
|
|
137
|
+
# --- Worker and namespace ---
|
|
138
|
+
|
|
139
|
+
worker childWorkflowsWorker:
|
|
140
|
+
workflow ParentWorkflow
|
|
141
|
+
workflow ChildWorkflow
|
|
142
|
+
workflow DeployApplication
|
|
143
|
+
workflow DeployInfrastructure
|
|
144
|
+
workflow DeployServices
|
|
145
|
+
workflow ParallelItemBatch
|
|
146
|
+
workflow ProcessItem
|
|
147
|
+
workflow Onboarding
|
|
148
|
+
workflow CreateAccount
|
|
149
|
+
workflow EnterpriseSetup
|
|
150
|
+
workflow StandardSetup
|
|
151
|
+
workflow SendWelcomeEmail
|
|
152
|
+
workflow ParentWithDetach
|
|
153
|
+
workflow NotifyCustomer
|
|
154
|
+
activity ValidateInput
|
|
155
|
+
activity TransformData
|
|
156
|
+
activity ProvisionDatabase
|
|
157
|
+
activity RunMigrations
|
|
158
|
+
activity BuildArtifacts
|
|
159
|
+
activity DeployContainers
|
|
160
|
+
activity ProcessSingleItem
|
|
161
|
+
activity CreateUserRecord
|
|
162
|
+
activity ConfigureEnterprise
|
|
163
|
+
activity ConfigureStandard
|
|
164
|
+
activity SendEmail
|
|
165
|
+
activity ProcessOrder
|
|
166
|
+
activity SendCustomerNotification
|
|
167
|
+
|
|
168
|
+
namespace deployment:
|
|
169
|
+
worker childWorkflowsWorker
|
|
170
|
+
options:
|
|
171
|
+
task_queue: "deployment"
|