Skip to content

Commit f751833

Browse files
committed
docs: continue the Temporal examples as new
Review found that the billing workflow continued as new only with an empty queue, and the game room workflow never did. Both now continue as new when Temporal suggests it and carry their state into the new run. Both still pass the time-skipping check. That check does not reach the Continue-As-New branch, and the page says so.
1 parent a984d39 commit f751833

1 file changed

Lines changed: 19 additions & 11 deletions

File tree

‎docs/compare/temporal.md‎

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ The task: a Rails 8 app on PostgreSQL syncs each customer's subscription with an
5959

6060
### With the Temporal Ruby SDK
6161

62-
There is one `CustomerBillingWorkflow` for each customer. This code follows the Temporal Ruby documentation. On October 18, 2026, it ran with the `temporalio` gem in the Temporal time-skipping test environment: three updates reached the billing API in order, and a failed push ran again with the same key. The Solid Objects test suite does not run it.
62+
There is one `CustomerBillingWorkflow` for each customer. This code follows the Temporal Ruby documentation. On October 18, 2026, it ran with the `temporalio` gem in the Temporal time-skipping test environment: three updates reached the billing API in order, and a failed push ran again with the same key. The Continue-As-New branch did not run in that check. The Solid Objects test suite does not run it.
6363

6464
```ruby
6565
require "temporalio/activity"
@@ -91,7 +91,7 @@ class CustomerBillingWorkflow < Temporalio::Workflow::Definition
9191
def execute(_state)
9292
loop do
9393
Temporalio::Workflow.wait_condition { @pending.any? || Temporalio::Workflow.continue_as_new_suggested }
94-
break if @pending.empty?
94+
break if Temporalio::Workflow.continue_as_new_suggested
9595

9696
update = @pending.first
9797
Temporalio::Workflow.execute_activity(
@@ -101,6 +101,7 @@ class CustomerBillingWorkflow < Temporalio::Workflow::Definition
101101
@last_synced_version = update.fetch("version")
102102
@pending.shift
103103
end
104+
Temporalio::Workflow.wait_condition { Temporalio::Workflow.all_handlers_finished? }
104105
raise Temporalio::Workflow::ContinueAsNewError.new(
105106
{ "last_synced_version" => @last_synced_version, "pending" => @pending }
106107
)
@@ -150,7 +151,7 @@ What to know:
150151
- Workflow code must be deterministic. It cannot read Active Record or call the billing API. The activity does that.
151152
- The state (`@pending` and `@last_synced_version`) lives in the event history, not in your tables. The app reads `last_synced_version` with a query.
152153
- Temporal counts the attempts of each activity. This workflow does not copy the retry count or the next retry time into its own state.
153-
- Each signal and each activity adds events to the history. The history is "limited to 51,200 Events or 50 MB", so the workflow continues as new when Temporal suggests it and no update is pending.
154+
- Each signal and each activity adds events to the history. The history is "limited to 51,200 Events or 50 MB", so the workflow continues as new when Temporal suggests it. It carries the pending updates into the new run.
154155
- Activities run at least once. The docs say that an activity "may be executed multiple times". The billing API must accept the idempotency key.
155156
- You operate a Temporal Service, or you use Temporal Cloud, and you run a worker process beside the Rails app.
156157

@@ -268,7 +269,7 @@ The task: turn-based game rooms in a Rails 8 app on PostgreSQL. Players send mov
268269

269270
### With the Temporal Ruby SDK
270271

271-
There is one `GameRoomWorkflow` for each room. This code also ran in the Temporal time-skipping test environment on October 18, 2026. A move out of turn was rejected, and the timer skipped a turn after 60 seconds.
272+
There is one `GameRoomWorkflow` for each room. This code also ran in the Temporal time-skipping test environment on October 18, 2026. A move out of turn was rejected, and the timer skipped a turn after 60 seconds. The Continue-As-New branch did not run in that check.
272273

273274
```ruby
274275
require "temporalio/workflow"
@@ -279,15 +280,17 @@ class GameRoomWorkflow < Temporalio::Workflow::Definition
279280
workflow_query_attr_reader :turn_number, :skipped_turns
280281

281282
workflow_init
282-
def initialize(players)
283-
@players = players
284-
@turn_number = 0
285-
@moves = []
286-
@skipped_turns = []
283+
def initialize(state)
284+
@players = state.fetch("players")
285+
@turn_number = state.fetch("turn_number")
286+
@moves = state.fetch("moves")
287+
@skipped_turns = state.fetch("skipped_turns")
287288
end
288289

289-
def execute(_players)
290+
def execute(_state)
290291
loop do
292+
break if Temporalio::Workflow.continue_as_new_suggested
293+
291294
turn = @turn_number
292295
Temporalio::Workflow.timeout(TURN_SECONDS) do
293296
Temporalio::Workflow.wait_condition { @turn_number > turn }
@@ -296,6 +299,10 @@ class GameRoomWorkflow < Temporalio::Workflow::Definition
296299
@skipped_turns << turn
297300
@turn_number += 1
298301
end
302+
Temporalio::Workflow.wait_condition { Temporalio::Workflow.all_handlers_finished? }
303+
raise Temporalio::Workflow::ContinueAsNewError.new(
304+
{ "players" => @players, "turn_number" => @turn_number, "moves" => @moves, "skipped_turns" => @skipped_turns }
305+
)
299306
end
300307

301308
workflow_update_validator(:play)
@@ -320,6 +327,7 @@ end
320327
```
321328

322329
- An update with a validator can reject a move, and the caller gets the error. A signal cannot do that. The server answers a signal "without waiting for the Workflow to process the Signal".
330+
- The workflow continues as new when Temporal suggests it, and carries the room state into the new run. So a long game stays inside the history limit.
323331
- `Temporalio::Workflow.timeout` starts a durable timer. "Timers are persisted", so the timer fires after a worker restart.
324332
- The Action Cable channel calls `execute_update` on the workflow handle. The docs say that a client that sends an update "must wait until the Server delivers the Update to a Worker".
325333

@@ -383,7 +391,7 @@ end
383391
- With no key, `schedule(at:)` gives an actor one alarm for each operation. Each new turn moves the alarm, so one room has one timer.
384392
- The reminder is a row in the database. Another process runs it after a restart.
385393

386-
[The tests](../../test/compare/game_room_test.rb) show that moves apply in the order they arrived, that a move out of turn or for an old turn is rejected, that a move moves the timer, and that the timer skips the turn after a restart.
394+
[The tests](../../test/compare/game_room_test.rb) show that moves apply in the order they arrived, that a move out of turn or for an old turn is rejected, that a move moves the timer, that an old timeout behind a move does not skip the next turn, and that the timer skips the turn after a restart.
387395

388396
## Questions that teams ask
389397

0 commit comments

Comments
 (0)