@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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/package.json +37 -0
  4. package/skills/MANIFEST.json +373 -0
  5. package/skills/MANIFEST.md +121 -0
  6. package/skills/temporal-architect/SKILL.md +99 -0
  7. package/skills/temporal-architect/reference/decomposition.md +78 -0
  8. package/skills/temporal-architect-author-go/README.md +16 -0
  9. package/skills/temporal-architect-author-go/SKILL.md +191 -0
  10. package/skills/temporal-architect-author-go/SUBAGENT_ADOPTION.md +161 -0
  11. package/skills/temporal-architect-author-go/reference/activity-call.md +73 -0
  12. package/skills/temporal-architect-author-go/reference/activity-def.md +54 -0
  13. package/skills/temporal-architect-author-go/reference/assignment.md +36 -0
  14. package/skills/temporal-architect-author-go/reference/await-all.md +104 -0
  15. package/skills/temporal-architect-author-go/reference/await-one.md +193 -0
  16. package/skills/temporal-architect-author-go/reference/await-timer.md +35 -0
  17. package/skills/temporal-architect-author-go/reference/close.md +71 -0
  18. package/skills/temporal-architect-author-go/reference/composite-patterns.md +176 -0
  19. package/skills/temporal-architect-author-go/reference/condition.md +56 -0
  20. package/skills/temporal-architect-author-go/reference/control-flow.md +151 -0
  21. package/skills/temporal-architect-author-go/reference/dependency-resolution.md +29 -0
  22. package/skills/temporal-architect-author-go/reference/detach.md +52 -0
  23. package/skills/temporal-architect-author-go/reference/heartbeat.md +84 -0
  24. package/skills/temporal-architect-author-go/reference/nexus-service-def.md +73 -0
  25. package/skills/temporal-architect-author-go/reference/nexus.md +35 -0
  26. package/skills/temporal-architect-author-go/reference/options.md +138 -0
  27. package/skills/temporal-architect-author-go/reference/promise.md +73 -0
  28. package/skills/temporal-architect-author-go/reference/proto-driven.md +197 -0
  29. package/skills/temporal-architect-author-go/reference/query-handler.md +34 -0
  30. package/skills/temporal-architect-author-go/reference/signal-handler.md +73 -0
  31. package/skills/temporal-architect-author-go/reference/three-layer-testing.md +173 -0
  32. package/skills/temporal-architect-author-go/reference/types.md +72 -0
  33. package/skills/temporal-architect-author-go/reference/update-handler.md +64 -0
  34. package/skills/temporal-architect-author-go/reference/worker.md +215 -0
  35. package/skills/temporal-architect-author-go/reference/workflow-call.md +37 -0
  36. package/skills/temporal-architect-author-go/reference/workflow-def.md +45 -0
  37. package/skills/temporal-architect-author-infra/README.md +16 -0
  38. package/skills/temporal-architect-author-infra/SKILL.md +132 -0
  39. package/skills/temporal-architect-author-infra/reference/tcld.md +112 -0
  40. package/skills/temporal-architect-author-infra/reference/terraform.md +125 -0
  41. package/skills/temporal-architect-design/README.md +16 -0
  42. package/skills/temporal-architect-design/SKILL.md +224 -0
  43. package/skills/temporal-architect-design/reference/LANGUAGE.md +5 -0
  44. package/skills/temporal-architect-design/reference/anti-patterns.md +332 -0
  45. package/skills/temporal-architect-design/reference/common-errors.md +88 -0
  46. package/skills/temporal-architect-design/reference/core-principles.md +52 -0
  47. package/skills/temporal-architect-design/reference/design-checklist.md +59 -0
  48. package/skills/temporal-architect-design/reference/namespaces.md +84 -0
  49. package/skills/temporal-architect-design/reference/notation-examples.md +304 -0
  50. package/skills/temporal-architect-design/reference/notation-reference.md +70 -0
  51. package/skills/temporal-architect-design/reference/primitives-reference.md +65 -0
  52. package/skills/temporal-architect-design/reference/project-discovery-subagent.md +80 -0
  53. package/skills/temporal-architect-design/reference/reverse-engineering.md +53 -0
  54. package/skills/temporal-architect-design/reference/twf-conventions.md +43 -0
  55. package/skills/temporal-architect-design/reference/workflow-boundaries.md +43 -0
  56. package/skills/temporal-architect-design/topics/activities-advanced.md +358 -0
  57. package/skills/temporal-architect-design/topics/activities-advanced.twf +107 -0
  58. package/skills/temporal-architect-design/topics/child-workflows.md +347 -0
  59. package/skills/temporal-architect-design/topics/child-workflows.twf +171 -0
  60. package/skills/temporal-architect-design/topics/long-running.md +230 -0
  61. package/skills/temporal-architect-design/topics/long-running.twf +100 -0
  62. package/skills/temporal-architect-design/topics/nexus.md +248 -0
  63. package/skills/temporal-architect-design/topics/nexus.twf +148 -0
  64. package/skills/temporal-architect-design/topics/patterns.md +469 -0
  65. package/skills/temporal-architect-design/topics/patterns.twf +346 -0
  66. package/skills/temporal-architect-design/topics/promises-conditions.md +179 -0
  67. package/skills/temporal-architect-design/topics/promises-conditions.twf +213 -0
  68. package/skills/temporal-architect-design/topics/signals-queries-updates.md +319 -0
  69. package/skills/temporal-architect-design/topics/signals-queries-updates.twf +234 -0
  70. package/skills/temporal-architect-design/topics/task-queues.md +205 -0
  71. package/skills/temporal-architect-design/topics/task-queues.twf +184 -0
  72. package/skills/temporal-architect-design/topics/testing.md +437 -0
  73. package/skills/temporal-architect-design/topics/testing.twf +177 -0
  74. package/skills/temporal-architect-design/topics/timers-scheduling.md +131 -0
  75. package/skills/temporal-architect-design/topics/timers-scheduling.twf +129 -0
  76. package/skills/temporal-architect-design/topics/versioning.md +434 -0
  77. package/skills/temporal-architect-design/topics/versioning.twf +174 -0
@@ -0,0 +1,148 @@
1
+ # Source: nexus.md
2
+ # Patterns: nexus service definitions, endpoint routing, cross-namespace calls
3
+
4
+ # --- Nexus service definition ---
5
+
6
+ nexus service PaymentsService:
7
+ async ProcessPayment workflow ProcessPaymentWorkflow
8
+ sync GetPaymentStatus(paymentId: string) -> (PaymentStatus):
9
+ activity LookupPayment(paymentId) -> status
10
+ close complete(status)
11
+
12
+ nexus service NotificationsService:
13
+ async SendConfirmation workflow SendConfirmationWorkflow
14
+
15
+ # --- Caller workflow using nexus ---
16
+
17
+ workflow OrderCheckout(order: Order) -> (OrderResult):
18
+ # Validate locally
19
+ activity ValidateCheckout(order)
20
+
21
+ # Call into payments via Nexus endpoint (child call)
22
+ nexus PaymentsEndpoint PaymentsService.ProcessPayment(order.payment) -> paymentResult
23
+
24
+ # Call into notifications (fire-and-forget)
25
+ detach nexus NotificationsEndpoint NotificationsService.SendConfirmation(order.customer, paymentResult)
26
+
27
+ close complete(OrderResult{paymentId: paymentResult.id})
28
+
29
+ # --- Async nexus call (promise) ---
30
+
31
+ workflow AsyncNexusCaller(data: Data) -> (Result):
32
+ # Start nexus call, get promise
33
+ promise paymentHandle <- nexus PaymentsEndpoint PaymentsService.ProcessPayment(data.payment)
34
+
35
+ # Do other work in parallel
36
+ activity DoLocalWork(data) -> localResult
37
+
38
+ # Wait for nexus result when needed
39
+ await paymentHandle -> paymentResult
40
+
41
+ close complete(Result{localResult, paymentResult})
42
+
43
+ # --- Nexus with options ---
44
+
45
+ workflow NexusWithOptions(payment: Payment) -> (PaymentResult):
46
+ nexus PaymentsEndpoint PaymentsService.ProcessPayment(payment) -> result
47
+ options:
48
+ schedule_to_close_timeout: 5m
49
+ close complete(PaymentResult{result})
50
+
51
+ # --- Nexus error handling with await one ---
52
+
53
+ workflow NexusWithTimeout(data: Data) -> (Result):
54
+ await one:
55
+ nexus PaymentsEndpoint PaymentsService.ProcessPayment(data) -> result:
56
+ close complete(Result{success: true, data: result})
57
+ timer(5m):
58
+ activity AlertTimeout(data)
59
+ close fail(Result{success: false, error: "timeout"})
60
+
61
+ # --- Supporting local activities ---
62
+
63
+ activity ValidateCheckout(order: Order):
64
+ validate(order)
65
+
66
+ activity DoLocalWork(data: Data) -> (LocalResult):
67
+ return process(data)
68
+
69
+ activity AlertTimeout(data: Data):
70
+ alert(data)
71
+
72
+ activity LookupPayment(paymentId: string) -> (PaymentStatus):
73
+ return lookup(paymentId)
74
+
75
+ # --- Target workflows ---
76
+
77
+ workflow ProcessPaymentWorkflow(payment: Payment) -> (PaymentResult):
78
+ activity ValidatePaymentDetails(payment)
79
+ activity ChargePaymentMethod(payment) -> result
80
+ activity RecordPaymentTransaction(result)
81
+ close complete(PaymentResult{id: result.id})
82
+
83
+ workflow SendConfirmationWorkflow(customer: Customer, paymentResult: PaymentResult):
84
+ activity SendPaymentConfirmation(customer.email, paymentResult)
85
+ close complete
86
+
87
+ # --- Supporting activities for target workflows ---
88
+
89
+ activity ValidatePaymentDetails(payment: Payment):
90
+ validate(payment)
91
+
92
+ activity ChargePaymentMethod(payment: Payment) -> (ChargeResult):
93
+ return charge(payment)
94
+
95
+ activity RecordPaymentTransaction(result: ChargeResult):
96
+ record(result)
97
+
98
+ activity SendPaymentConfirmation(email: string, data: PaymentResult):
99
+ send(email, data)
100
+
101
+ # --- Worker and namespace definitions ---
102
+
103
+ worker paymentProcessingWorker:
104
+ workflow ProcessPaymentWorkflow
105
+ activity ValidatePaymentDetails
106
+ activity ChargePaymentMethod
107
+ activity RecordPaymentTransaction
108
+ activity LookupPayment
109
+ nexus service PaymentsService
110
+
111
+ worker notificationWorker:
112
+ workflow SendConfirmationWorkflow
113
+ activity SendPaymentConfirmation
114
+ nexus service NotificationsService
115
+
116
+ worker checkoutWorker:
117
+ workflow OrderCheckout
118
+ workflow AsyncNexusCaller
119
+ workflow NexusWithOptions
120
+ workflow NexusWithTimeout
121
+ activity ValidateCheckout
122
+ activity DoLocalWork
123
+ activity AlertTimeout
124
+
125
+ # Three separate namespaces — the defining feature of Nexus.
126
+ # Endpoints live in the target namespace alongside the workers that serve them.
127
+ # The caller namespace (orders) just references endpoint names in its workflows.
128
+
129
+ namespace payments:
130
+ worker paymentProcessingWorker
131
+ options:
132
+ task_queue: "payments"
133
+ nexus endpoint PaymentsEndpoint
134
+ options:
135
+ task_queue: "payments"
136
+
137
+ namespace notifications:
138
+ worker notificationWorker
139
+ options:
140
+ task_queue: "notifications"
141
+ nexus endpoint NotificationsEndpoint
142
+ options:
143
+ task_queue: "notifications"
144
+
145
+ namespace orders:
146
+ worker checkoutWorker
147
+ options:
148
+ task_queue: "checkout"
@@ -0,0 +1,469 @@
1
+ # Workflow Patterns
2
+
3
+ > **Example:** [`patterns.twf`](./patterns.twf)
4
+
5
+ Common patterns for structuring Temporal workflows. Choose based on your use case characteristics.
6
+
7
+ ## Pattern Overview
8
+
9
+ | Pattern | Use When | Example |
10
+ |---------|----------|---------|
11
+ | **Process** | Discrete operation with start and end | Order fulfillment |
12
+ | **Entity** | Long-lived, represents a thing | User account |
13
+ | **Saga** | Distributed transaction with compensation | Multi-service booking |
14
+ | **Fan-Out/Fan-In** | Parallel processing with aggregation | Batch processing |
15
+ | **Pipeline** | Sequential stages of transformation | Data processing |
16
+ | **State Machine** | Explicit state transitions | Document approval |
17
+ | **Polling** | Wait for external condition | Resource provisioning |
18
+
19
+ ---
20
+
21
+ ## Process Workflow
22
+
23
+ A discrete operation that drives toward completion.
24
+
25
+ ### Characteristics
26
+ - Has a clear start and end
27
+ - Progresses through defined steps
28
+ - Returns a result when complete
29
+ - Relatively short-lived (minutes to hours)
30
+
31
+ ### Pattern
32
+
33
+ ```twf
34
+ workflow OrderFulfillment(order: Order) -> (OrderResult):
35
+ # Step 1: Validate
36
+ activity ValidateRetailOrder(order) -> validated
37
+ if not validated.success:
38
+ close fail(OrderResult{status: "invalid", error: validated.error})
39
+
40
+ # Step 2: Reserve
41
+ activity ReserveInventory(order.items) -> reservation
42
+
43
+ # Step 3: Charge
44
+ activity ProcessPayment(order.payment) -> payment
45
+
46
+ # Step 4: Fulfill
47
+ activity ShipRetailOrder(order, reservation)
48
+
49
+ # Step 5: Notify
50
+ activity SendConfirmation(order.customer)
51
+
52
+ close complete(OrderResult{status: "completed", trackingId: reservation.trackingId})
53
+ ```
54
+
55
+ ### When to Use
56
+ - Order processing
57
+ - User registration
58
+ - Deployment pipelines
59
+ - Report generation
60
+
61
+ ---
62
+
63
+ ## Entity Workflow
64
+
65
+ A long-running workflow representing a business entity.
66
+
67
+ ### Characteristics
68
+ - Long-lived (days, months, indefinitely)
69
+ - Reacts to external events (signals)
70
+ - Maintains state over time
71
+ - Uses continue-as-new to manage history
72
+
73
+ ### Pattern
74
+
75
+ Handlers (`signal`/`query`/`update`) are declared **before** the workflow body, not after it. `history_length()` returns an event *count* (use it against an event-count threshold); `history_size()` returns *bytes* (use it against a byte limit) — don't confuse the two.
76
+
77
+ ```twf
78
+ workflow AccountEntity(accountId: string, account: Account):
79
+ query GetBalance() -> (decimal):
80
+ return account.balance
81
+
82
+ update Transfer(amount: decimal, toAccount: string) -> (TransferResult):
83
+ if account.balance < amount:
84
+ return TransferResult{success: false, error: "insufficient funds"}
85
+ account.balance -= amount
86
+ activity InitiateTransfer(toAccount, amount)
87
+ return TransferResult{success: true}
88
+
89
+ if account == null:
90
+ activity LoadAccount(accountId) -> account
91
+
92
+ for:
93
+ await one:
94
+ signal Deposit:
95
+ account.balance += signal.amount
96
+ activity RecordAccountTransaction(accountId, "deposit", signal.amount)
97
+
98
+ signal Withdraw:
99
+ if account.balance >= signal.amount:
100
+ account.balance -= signal.amount
101
+ activity RecordAccountTransaction(accountId, "withdraw", signal.amount)
102
+
103
+ signal Close:
104
+ activity CloseAccount(accountId)
105
+ close complete
106
+
107
+ timer(24h):
108
+ activity DailyReconciliation(accountId, account)
109
+
110
+ # history_length() = event count; reset before it grows large
111
+ if history_length() > 1000:
112
+ close continue_as_new(accountId, account)
113
+ ```
114
+
115
+ ### When to Use
116
+ - User accounts
117
+ - Subscriptions
118
+ - Shopping carts
119
+ - IoT device state
120
+ - Game sessions
121
+
122
+ ---
123
+
124
+ ## Saga Pattern
125
+
126
+ Distributed transaction with compensation for failures.
127
+
128
+ ### Characteristics
129
+ - Multiple services/steps that must all succeed or all roll back
130
+ - Each step has a compensating action
131
+ - Compensation runs in reverse order on failure
132
+ - Provides eventual consistency
133
+
134
+ ### Pattern
135
+
136
+ > Note: The saga pattern requires error-handling constructs (try/catch, compensation stacks) that are expressed here as conceptual pseudo-code. See [`patterns.twf`](./patterns.twf) for the TWF syntax version.
137
+
138
+ ```pseudo
139
+ workflow BookingWorkflow(booking: Booking) -> BookingResult:
140
+ # Step 1: Reserve flight
141
+ activity ReserveFlight(booking.flight) -> flight
142
+
143
+ # Step 2: Reserve hotel (compensate flight on failure)
144
+ activity ReserveHotel(booking.hotel) -> hotel
145
+ # on failure: activity CancelFlight(flight.id)
146
+
147
+ # Step 3: Reserve car (compensate hotel + flight on failure)
148
+ activity ReserveCar(booking.car) -> car
149
+ # on failure: activity CancelHotel(hotel.id), activity CancelFlight(flight.id)
150
+
151
+ # Step 4: Charge payment (compensate all on failure)
152
+ activity ChargeBookingPayment(booking.payment) -> payment
153
+ # on failure: activity CancelCar(car.id), CancelHotel(...), CancelFlight(...)
154
+
155
+ # All succeeded
156
+ close complete(BookingResult{status: "confirmed", flight, hotel, car, payment})
157
+
158
+ # On any step failure, compensations run in reverse order
159
+ # SDK-level error handling drives the compensation logic
160
+ ```
161
+
162
+ ### Compensation Design
163
+
164
+ | Step | Forward Action | Compensation |
165
+ |------|---------------|--------------|
166
+ | Reserve | Create pending reservation | Cancel reservation |
167
+ | Charge | Process payment | Refund payment |
168
+ | Ship | Create shipment | Cancel shipment |
169
+ | Provision | Create resource | Delete resource |
170
+
171
+ ### When to Use
172
+ - Multi-service transactions
173
+ - Booking systems (travel, events)
174
+ - Financial operations
175
+ - Resource provisioning
176
+
177
+ ---
178
+
179
+ ## Fan-Out/Fan-In Pattern
180
+
181
+ Process items in parallel, aggregate results.
182
+
183
+ ### Characteristics
184
+ - Split work into parallel tasks
185
+ - Each task executes independently
186
+ - Aggregate results when all complete
187
+ - Handle partial failures
188
+
189
+ ### Pattern
190
+
191
+ > Note: The TWF DSL currently re-binds the result variable on each iteration of `await all: for`. The aggregation step below is expressed as conceptual pseudo-code. See [`patterns.twf`](./patterns.twf) for the TWF syntax version.
192
+
193
+ ```twf
194
+ workflow BatchProcessor(items: []Item) -> (BatchResult):
195
+ # Fan-out: start all processing in parallel
196
+ await all:
197
+ for (item in items):
198
+ activity ProcessItem(item) -> result
199
+
200
+ # Fan-in: aggregate results (conceptual -- SDK collects results)
201
+ activity AggregateResults(items) -> aggregated
202
+
203
+ close complete(BatchResult{results: aggregated})
204
+ ```
205
+
206
+ ### Variations
207
+
208
+ **With Concurrency Limit:**
209
+ ```twf
210
+ workflow RateLimitedBatch(items: []Item) -> (BatchResult):
211
+ # Process in batches of 10
212
+ for (batch in chunk(items, 10)):
213
+ await all:
214
+ for (item in batch):
215
+ activity ProcessItem(item) -> result
216
+
217
+ close complete(BatchResult{})
218
+ ```
219
+
220
+ **With Result Selection:**
221
+ ```twf
222
+ workflow FirstSuccessful(sources: []Source) -> (Data):
223
+ await all:
224
+ for (source in sources):
225
+ activity TryFetch(source) -> result
226
+
227
+ # SDK-level: find first successful result
228
+ activity FindFirstSuccess(sources) -> data
229
+ close complete(data)
230
+ ```
231
+
232
+ ### When to Use
233
+ - Batch processing
234
+ - Parallel API calls
235
+ - Distributed computation
236
+ - Report aggregation
237
+
238
+ ---
239
+
240
+ ## Pipeline Pattern
241
+
242
+ Sequential transformation stages.
243
+
244
+ ### Characteristics
245
+ - Data flows through ordered stages
246
+ - Each stage transforms and passes to next
247
+ - Clear separation of concerns
248
+ - Easy to add/remove stages
249
+
250
+ ### Pattern
251
+
252
+ ```twf
253
+ workflow DataPipeline(rawData: RawData) -> (ProcessedData):
254
+ # Stage 1: Ingest
255
+ activity Ingest(rawData) -> ingested
256
+
257
+ # Stage 2: Validate
258
+ activity Validate(ingested) -> validated
259
+ if not validated.valid:
260
+ close fail(ProcessedData{status: "invalid", errors: validated.errors})
261
+
262
+ # Stage 3: Transform
263
+ activity Transform(validated.data) -> transformed
264
+
265
+ # Stage 4: Enrich
266
+ activity Enrich(transformed) -> enriched
267
+
268
+ # Stage 5: Load
269
+ activity Load(enriched)
270
+
271
+ close complete(ProcessedData{status: "complete", recordCount: enriched.count})
272
+ ```
273
+
274
+ ### With Conditional Stages
275
+
276
+ ```twf
277
+ workflow AdaptivePipeline(data: Data) -> (Result):
278
+ activity Parse(data) -> processed
279
+
280
+ if processed.needsEnrichment:
281
+ activity Enrich(processed) -> processed
282
+
283
+ if processed.format == "legacy":
284
+ activity ConvertLegacy(processed) -> processed
285
+
286
+ activity Finalize(processed) -> result
287
+ close complete(result)
288
+ ```
289
+
290
+ ### When to Use
291
+ - ETL processes
292
+ - Document processing
293
+ - Media transcoding
294
+ - Data migrations
295
+
296
+ ---
297
+
298
+ ## State Machine Pattern
299
+
300
+ Explicit states and transitions.
301
+
302
+ ### Characteristics
303
+ - Well-defined states
304
+ - Explicit transition rules
305
+ - Events trigger transitions
306
+ - Clear audit trail
307
+
308
+ ### Pattern
309
+
310
+ ```twf
311
+ workflow DocumentApproval(doc: Document) -> (ApprovalResult):
312
+ signal Submit():
313
+ phase = "pending_review"
314
+ activity NotifyReviewers(doc)
315
+
316
+ signal Approve():
317
+ phase = "approved"
318
+
319
+ signal Reject():
320
+ phase = "rejected"
321
+
322
+ signal RequestChanges():
323
+ phase = "changes_requested"
324
+
325
+ signal Withdraw():
326
+ phase = "withdrawn"
327
+
328
+ query GetPhase() -> (string):
329
+ return phase
330
+
331
+ phase = "draft"
332
+
333
+ for:
334
+ switch (phase):
335
+ case "draft":
336
+ await one:
337
+ signal Submit:
338
+ timer(90d):
339
+ phase = "expired"
340
+ case "pending_review":
341
+ await one:
342
+ signal Approve:
343
+ signal Reject:
344
+ signal RequestChanges:
345
+ timer(30d):
346
+ phase = "expired"
347
+ case "changes_requested":
348
+ await one:
349
+ signal Submit:
350
+ signal Withdraw:
351
+ timer(30d):
352
+ phase = "expired"
353
+ case "approved":
354
+ activity PublishDocument(doc)
355
+ close complete(ApprovalResult{status: "approved"})
356
+ case "rejected":
357
+ activity ArchiveDocument(doc)
358
+ close complete(ApprovalResult{status: "rejected"})
359
+ case "withdrawn":
360
+ close complete(ApprovalResult{status: "withdrawn"})
361
+ case "expired":
362
+ close complete(ApprovalResult{status: "expired"})
363
+ ```
364
+
365
+ ### State Transition Table
366
+
367
+ | From State | Event | To State | Action |
368
+ |------------|-------|----------|--------|
369
+ | draft | Submit | pending_review | Notify reviewers |
370
+ | pending_review | Approve | approved | None |
371
+ | pending_review | Reject | rejected | None |
372
+ | pending_review | RequestChanges | changes_requested | None |
373
+ | changes_requested | Submit | pending_review | None |
374
+ | changes_requested | Withdraw | withdrawn | None |
375
+ | draft | Timer(90d) | expired | Auto-expire |
376
+ | pending_review | Timer(30d) | expired | Auto-expire |
377
+ | changes_requested | Timer(30d) | expired | Auto-expire |
378
+
379
+ ### When to Use
380
+ - Approval workflows
381
+ - Order status tracking
382
+ - Support tickets
383
+ - Insurance claims
384
+
385
+ ---
386
+
387
+ ## Polling Pattern
388
+
389
+ Wait for external condition to be met.
390
+
391
+ ### Characteristics
392
+ - External system doesn't push updates
393
+ - Must poll periodically
394
+ - Need backoff strategy
395
+ - Has timeout/deadline
396
+
397
+ ### Pattern
398
+
399
+ ```twf
400
+ workflow AwaitResourceReady(resourceId: string) -> (Resource):
401
+ backoff = 5s
402
+ maxBackoff = 60s
403
+
404
+ for:
405
+ activity CheckResourceStatus(resourceId) -> status
406
+
407
+ if status.ready:
408
+ activity GetResource(resourceId) -> resource
409
+ close complete(resource)
410
+
411
+ if status.failed:
412
+ activity CancelProvisioning(resourceId)
413
+ close fail(ProvisioningError{error: status.error})
414
+
415
+ # Wait with backoff, deadline via await one + timer
416
+ await one:
417
+ timer(backoff):
418
+ backoff = min(backoff * 2, maxBackoff)
419
+ timer(30m):
420
+ activity CancelProvisioning(resourceId)
421
+ close fail(ProvisioningTimeout{})
422
+ ```
423
+
424
+ ### With Progress Updates
425
+
426
+ > Note: `upsert_search_attributes` is an SDK-level call, not TWF notation.
427
+
428
+ ```twf
429
+ workflow MonitorJob(jobId: string) -> (JobResult):
430
+ for:
431
+ activity GetJobStatus(jobId) -> status
432
+
433
+ # Update search attributes for visibility (SDK call)
434
+ # upsert_search_attributes({JobProgress: status.percentComplete, JobStage: status.currentStage})
435
+
436
+ if status.complete:
437
+ activity GetJobResult(jobId) -> result
438
+ close complete(result)
439
+
440
+ await timer(30s)
441
+ ```
442
+
443
+ ### When to Use
444
+ - Resource provisioning
445
+ - External job monitoring
446
+ - Third-party integrations
447
+ - CI/CD pipelines
448
+
449
+ ---
450
+
451
+ ## Pattern Selection Guide
452
+
453
+ ```text
454
+ Start
455
+
456
+ ├─ Is it a long-lived entity? ──────────────► Entity Pattern
457
+
458
+ ├─ Does it need distributed rollback? ──────► Saga Pattern
459
+
460
+ ├─ Can items be processed in parallel? ─────► Fan-Out/Fan-In
461
+
462
+ ├─ Is it a series of transformations? ──────► Pipeline Pattern
463
+
464
+ ├─ Are there explicit states/transitions? ──► State Machine
465
+
466
+ ├─ Need to wait for external condition? ────► Polling Pattern
467
+
468
+ └─ Simple start-to-finish process? ─────────► Process Workflow
469
+ ```