From 40180b84fbfc8f30d66f6916c383099ea2b55cdc Mon Sep 17 00:00:00 2001 From: nadvolod <2136245+nadvolod@users.noreply.github.com> Date: Sat, 14 Nov 2026 13:18:11 -0500 Subject: [PATCH 1/4] Move the Saga up, give it 30 minutes, make Heartbeats a Stretch Workshop - The Saga section and its lab run straight after the Quiz, ahead of Child Workflows, Continue-As-New and Heartbeats; the agenda follows. - Saga lab: 25 -> 30 minutes. - Labs block: Child Workflows and Continue-As-New core (25 minutes); Heartbeats offered to early finishers on both lab slides. Its slides are still taught to everyone. - CONTEXT.md: new term, Stretch Workshop (live delivery only). - ADR 0005 records the decision and the options rejected. - Child Workflows notes: the Saga reference now points back. Co-Authored-By: Claude Opus 5.5 --- CONTEXT.md | 7 ++ .../segments/14-child-workflows.md | 4 +- decks/java-master/slides.md | 111 ++++++++++-------- ...stretch-workshop-and-saga-gets-its-time.md | 37 ++++++ 4 files changed, 107 insertions(+), 52 deletions(-) create mode 100644 docs/adr/0005-heartbeats-is-a-stretch-workshop-and-saga-gets-its-time.md diff --git a/CONTEXT.md b/CONTEXT.md index 2d20b1b..01a8ac3 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -77,6 +77,13 @@ Core TODOs are required to finish; Stretch TODOs are optional extras for learner who finish early, and nothing later depends on them. _Avoid_: starter, skeleton, template +**Stretch Workshop**: +A Workshop whose Track is offered, in every Dev Day, only to learners who +finish early. Everyone still sees its Deck segment; nothing later in a Dev Day +depends on its Track. It describes live delivery only: on its own, the +Workshop and its Track are like any other. +_Avoid_: bonus lab, optional workshop, extra + **Solution**: The completed counterpart of an Exercise, structurally identical to it. _Avoid_: answer, final, complete diff --git a/decks/java-master/segments/14-child-workflows.md b/decks/java-master/segments/14-child-workflows.md index 93525c4..7408c37 100644 --- a/decks/java-master/segments/14-child-workflows.md +++ b/decks/java-master/segments/14-child-workflows.md @@ -117,8 +117,8 @@ closes, and only the child's lane changes. one people misunderstand: the child keeps running even though the parent is gone. That is intentional, and powerful for fire-and-forget sub-processes. - **Click 3 - `REQUEST_CANCEL`.** The child is sent a cancellation request and - can clean up gracefully, the same cancellation the Saga section uses to run - compensations, before it ends as cancelled. + can clean up gracefully before it ends as cancelled: the cancellation the + Saga section pointed to, where compensations still run in a detached scope. The policy applies whenever the parent closes, whether it completed, failed, timed out or was terminated. Not only on failure. In code these are diff --git a/decks/java-master/slides.md b/decks/java-master/slides.md index 1557fbd..f2304e4 100644 --- a/decks/java-master/slides.md +++ b/decks/java-master/slides.md @@ -52,14 +52,14 @@ themeConfig: label: Updates - id: quiz label: Quiz + - id: saga + label: "Compensations: the Saga pattern" - id: child label: Child Workflows - id: can label: Continue-As-New - id: heartbeats label: Heartbeats - - id: saga - label: "Compensations: the Saga pattern" - id: patterns label: Patterns and anti-patterns - id: claim-check @@ -198,7 +198,7 @@ layout: section # Advanced Temporal Topics -Child Workflows, Continue‑As‑New, Heartbeats, Sagas, and beyond. +Sagas, Child Workflows, Continue‑As‑New, Heartbeats, and beyond. @@ -214,52 +214,6 @@ post); there is no official wizard version, so check with brand before using it outside a workshop. --> ---- -src: ./segments/14-child-workflows.md ---- - ---- -src: ./segments/15-continue-as-new.md ---- - ---- -src: ./segments/16-heartbeating.md ---- - ---- -layout: exercise -minutes: 35 -heading: Labs ---- - - - -- Child Workflows · 15 min -- Continue-As-New · 10 min -- Heartbeats · 10 min - - - --- layout: section --- @@ -309,20 +263,77 @@ src: ./segments/17-saga-07-related.md --- layout: exercise -minutes: 25 +minutes: 30 heading: "Lab: The Saga Pattern" --- +Finished early? **Heartbeats** · 10 min + +--- +src: ./segments/14-child-workflows.md +--- + +--- +src: ./segments/15-continue-as-new.md +--- + +--- +src: ./segments/16-heartbeating.md +--- + +--- +layout: exercise +minutes: 25 +heading: Labs +--- + + + +- Child Workflows · 15 min +- Continue-As-New · 10 min + +Finished early? **Heartbeats** · 10 min + + + --- src: ./segments/17b-patterns-and-anti-patterns.md --- diff --git a/docs/adr/0005-heartbeats-is-a-stretch-workshop-and-saga-gets-its-time.md b/docs/adr/0005-heartbeats-is-a-stretch-workshop-and-saga-gets-its-time.md new file mode 100644 index 0000000..efe0244 --- /dev/null +++ b/docs/adr/0005-heartbeats-is-a-stretch-workshop-and-saga-gets-its-time.md @@ -0,0 +1,37 @@ +# Heartbeats is a Stretch Workshop, and the Saga lab gets its time + +Learners rate the Saga Workshop the most useful lab of a Dev Day, so every +Deck gives it more room and an earlier slot. The Saga section and its lab run +straight after the Quiz, ahead of Child Workflows, Continue-As-New and +Heartbeats, and the lab gets 30 minutes instead of 25. + +The time comes from Heartbeats, which becomes a Stretch Workshop in every Deck: +its slides are still taught to everyone, but its Track is offered only to +learners who finish early, on both the Saga lab slide and the Labs slide. +Child Workflows (15 minutes) and Continue-As-New (10 minutes) stay core, so the +Labs block drops from 35 to 25 minutes and the day comes out 5 minutes shorter, +kept as buffer. + +Stretch describes live delivery only. The Heartbeats Workshop, its Track and +its README row are unchanged; someone taking the Track on their own sees an +ordinary Workshop. + +## Considered Options + +- **Child Workflows as the Stretch Workshop** was rejected: it is the only one + of the three at the Foundations Level, and it teaches composition every later + pattern uses. +- **Continue-As-New as the Stretch Workshop** was considered; learner feedback + pointed at Heartbeats instead. +- **A STRETCH Challenge inside the Saga Track** was considered for early + finishers and not added: the Saga's four Challenges fill the 30 minutes. +- **Marking Heartbeats as Stretch in the README index** was rejected: Stretch is + about how a Dev Day is run, not about the Workshop. + +## Consequences + +The Saga section now comes before Child Workflows, so the Child Workflows +segment's mention of the Saga section points back to something already taught. + +The Python and TypeScript DevDays repos keep their own order until the same +change is made there. From 8261607ed09c4eeaabe8d921c779aec2c66153bb Mon Sep 17 00:00:00 2001 From: nadvolod <2136245+nadvolod@users.noreply.github.com> Date: Sat, 14 Nov 2026 14:54:18 -0500 Subject: [PATCH 2/4] Ask why Temporal doesn't default to Continue-As-New A question slide after "What is Continue-As-New?": the room answers, then two clicks reveal that only your code knows what state to carry forward, and the three reasons (history is the state, it needs a safe point, most Workflows never need it), explained in the speaker notes. Co-Authored-By: Claude Opus 5.5 --- .../segments/15-continue-as-new.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/decks/java-master/segments/15-continue-as-new.md b/decks/java-master/segments/15-continue-as-new.md index 2842a06..c92266f 100644 --- a/decks/java-master/segments/15-continue-as-new.md +++ b/decks/java-master/segments/15-continue-as-new.md @@ -89,6 +89,43 @@ Worker Versioning, a Pinned run's continuation inherits its version unless you ask for `AUTO_UPGRADE`.) --> +--- +layout: center +class: text-center +--- + +

Why doesn't Temporal default to Continue‑As‑New?

+ +

Only your code knows what state to carry forward.

+ +
+ +History is the state · It needs a safe point · Most Workflows never need it + +
+ + + --- layout: code-walkthrough heading: "Continue-As-New in practice: a monthly subscription" From 8b5ec6c04ad0b9fbf3ca1efcf638086794a77311 Mon Sep 17 00:00:00 2001 From: nadvolod <2136245+nadvolod@users.noreply.github.com> Date: Sat, 14 Nov 2026 14:55:03 -0500 Subject: [PATCH 3/4] Name the cleanup a run needs before it continues as new The second reason on the question slide becomes "It needs cleanup first": finish handlers, drain buffered Signals, settle pending Activities and Child Workflows, and release anything held outside Temporal. Co-Authored-By: Claude Opus 5.5 --- .../segments/15-continue-as-new.md | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/decks/java-master/segments/15-continue-as-new.md b/decks/java-master/segments/15-continue-as-new.md index c92266f..fd5871d 100644 --- a/decks/java-master/segments/15-continue-as-new.md +++ b/decks/java-master/segments/15-continue-as-new.md @@ -100,7 +100,7 @@ class: text-center
-History is the state · It needs a safe point · Most Workflows never need it +History is the state · It needs cleanup first · Most Workflows never need it
@@ -113,10 +113,20 @@ and the second click is why that is not the reason. and the state goes with it, unless something carries it across. That something is the input to the new run, and only your code knows what belongs in it: `cyclesCompleted` yes, the loop's scratch variables no. -- **It needs a safe point.** In-flight work does not come along: pending - Activities, Timers, and Signal or Update handlers still running. Your code - knows when it is between steps (after a charge, before the next sleep); the - Server does not. +- **It needs cleanup first.** In-flight work does not come along, so the + current run has to wind down before it hands over, and only your code knows + what that takes: + - let running Signal and Update handlers finish: + `Workflow.await(() -> Workflow.isEveryHandlerFinished())`; + - drain Signals buffered in a field (a queue of pending changes) by + processing them or passing them in the new run's input, or they are lost; + - wait for or cancel pending Activities, and decide what happens to running + Child Workflows (their Parent Close Policy); + - release anything held outside Temporal, such as a lease or a reservation, + through an Activity. + + Then continue at a point between steps (after a charge, before the next + sleep). The Server cannot tell when the run is in that state. - **Most Workflows never need it.** An order, a transfer, a Saga finishes in hundreds of Events, far below the limits. One unbroken history is also the better audit trail and debugging record, and a new run means a new Run ID From 575679525afcf20b2bf0b42d8feb727d32f6e44f Mon Sep 17 00:00:00 2001 From: nadvolod <2136245+nadvolod@users.noreply.github.com> Date: Sat, 14 Nov 2026 15:01:28 -0500 Subject: [PATCH 4/4] Show Continue-As-New as one Workflow ID with a chain of runs A diagram slide after "What is Continue-As-New?": run 1's history nears the limit, it continues as new handing over only cyclesCompleted, and each new run starts with a fresh history under the same Workflow ID. Co-Authored-By: Claude Opus 5.5 --- .../components/ContinueAsNewRuns.vue | 112 ++++++++++++++++++ .../segments/15-continue-as-new.md | 25 ++++ 2 files changed, 137 insertions(+) create mode 100644 decks/java-master/components/ContinueAsNewRuns.vue diff --git a/decks/java-master/components/ContinueAsNewRuns.vue b/decks/java-master/components/ContinueAsNewRuns.vue new file mode 100644 index 0000000..e3fa2a2 --- /dev/null +++ b/decks/java-master/components/ContinueAsNewRuns.vue @@ -0,0 +1,112 @@ + + + + + + diff --git a/decks/java-master/segments/15-continue-as-new.md b/decks/java-master/segments/15-continue-as-new.md index fd5871d..fe137c2 100644 --- a/decks/java-master/segments/15-continue-as-new.md +++ b/decks/java-master/segments/15-continue-as-new.md @@ -61,6 +61,31 @@ from the Workflow ID alone follows the chain: `WorkflowStub.getResult(...)` waits for the last run. --> +--- +layout: default +clicks: 2 +--- + +# One Workflow, many runs + + + + + --- layout: default ---