Skip to content

fix(durable): don't journal a step whose context ended partway - #234

Draft
reka18 wants to merge 1 commit into
fix/durable-handle-lock-failed-appendfrom
fix/durable-canceled-service
Draft

reka18 wants to merge 1 commit into
fix/durable-handle-lock-failed-appendfrom
fix/durable-canceled-service

Conversation

@reka18

@reka18 reka18 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

What this change does

A step whose context ended partway is no longer journaled. Stacked on #233.

  • RunService: a settle the kernel refused returns true and ErrHandleFailed, wrapping the error, and journals nothing. After Recover the service stays in flight, so it runs a second time when the host calls RunService. Please check that this is the behavior you want.
  • Tick: a due timer the kernel refused returns ErrHandleFailed and journals nothing. Recover re-arms the timer. durable: defects found in the platform-redesign review #214 doesn't list this one, but it's the same defect.
  • DeliverToActor: a context that ended during the delivery returns ErrHandleFailed and journals nothing. The actor restarts from its initial state after Recover. Before this, a canceled delivery could make every later Recover fail. durable: defects found in the platform-redesign review #214 doesn't list this one either.
  • The "exactly once" docs for services and actors now say a recorded result never re-runs, and an unrecorded one does.
  • Recover and StateAt now fail on a canceled context, checked before each replayed Record, because a replayed settle or tick could stop silently and return state short of the journal.

Known and left open: a Fire canceled through a middleware's own derived context bypasses these guards, which only watch the caller's context.

Why

The kernel refused the step live, but the result was journaled, so recovery committed something the live instance never applied. For an actor, it left a journal Recover couldn't replay.

Relates to: #214

Evidence

On GOTOOLCHAIN=go1.27.3, in durable:

Command Result
go test ./... Pass, including TestService_ResultFromCanceledTurn_NotCommittedOnRecover and TestService_CanceledTurn_RecoverRerunsTheService

Checklist

  • Commits are signed off (git commit -s) per the DCO
  • Conventional commit messages (type: subject)
  • mage check passes locally (lint + race tests + govulncheck): not run as a whole
  • Tests added/updated for the change
  • Public API changes documented (godoc) and, if applicable, noted for the changelog

@reka18 reka18 added not-ready On every new PR until all review dimensions are confirmed wait:correctness ACR pending: correctness wait:regression-safety ACR pending: regression-safety wait:concurrency-discipline ACR pending: concurrency-discipline wait:replay-determinism ACR pending: replay-determinism wait:api-compatibility ACR pending: api-compatibility wait:missed-context ACR pending: missed-context wait:human-readability ACR pending: human-readability labels Nov 5, 2026
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 15ab425 to 41bfbb4 Compare November 5, 2026 16:38
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 41bfbb4 to f87bc98 Compare November 5, 2026 16:40
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from f87bc98 to 8c4ce15 Compare November 5, 2026 16:53
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 8c4ce15 to 83c5655 Compare November 5, 2026 17:09
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 83c5655 to 1023215 Compare November 5, 2026 17:14
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 1023215 to 1890a2c Compare November 5, 2026 17:22
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 1890a2c to 2e345fa Compare November 5, 2026 17:33
@reka18
reka18 added this pull request to stack #238 November 5, 2026 17:34
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 2e345fa to 96cceff Compare November 5, 2026 17:42
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 96cceff to 0d6f9ce Compare November 5, 2026 18:04
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 0d6f9ce to f6c246d Compare November 5, 2026 18:20
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 8c3e849 to d1c40fc Compare November 5, 2026 19:28
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from d1c40fc to 95201e6 Compare November 5, 2026 20:23
@reka18
reka18 removed this pull request from stack #238 November 5, 2026 20:26
@reka18
reka18 added this pull request to stack #239 November 5, 2026 20:26
@reka18
reka18 force-pushed the fix/durable-canceled-service branch from 95201e6 to 44571d6 Compare November 5, 2026 21:02
@reka18 reka18 added ready All ACR dimensions confirmed - clear to merge confirmed:correctness ACR clean: correctness confirmed:regression-safety ACR clean: regression-safety confirmed:concurrency-discipline ACR clean: concurrency-discipline confirmed:replay-determinism ACR clean: replay-determinism confirmed:api-compatibility ACR clean: api-compatibility confirmed:missed-context ACR clean: missed-context confirmed:human-readability ACR clean: human-readability and removed not-ready On every new PR until all review dimensions are confirmed wait:correctness ACR pending: correctness wait:regression-safety ACR pending: regression-safety wait:concurrency-discipline ACR pending: concurrency-discipline wait:replay-determinism ACR pending: replay-determinism wait:api-compatibility ACR pending: api-compatibility wait:missed-context ACR pending: missed-context wait:human-readability ACR pending: human-readability labels Nov 5, 2026
@reka18

reka18 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Review results. One reviewer per dimension, each reading the others' findings. All seven dimensions have zero blockers on the latest round.

Fixed along the way: Tick and DeliverToActor got the same partway guard as RunService, and Recover and StateAt check the context before each Record. The canceled-turn test moved here from #213 and now asserts the live state.

A context ended during RunService, Tick or DeliverToActor stops the kernel's
Fire, but the result was journaled anyway. Recovery then committed something
the live instance never applied, or for an actor, failed on every attempt.
Each now returns ErrHandleFailed and records nothing. Recover and StateAt fail
on a canceled context instead of returning state short of the journal.

Relates to #214.

Signed-off-by: Ray Karnes <ray.karnes@stablekernel.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

confirmed:api-compatibility ACR clean: api-compatibility confirmed:concurrency-discipline ACR clean: concurrency-discipline confirmed:correctness ACR clean: correctness confirmed:human-readability ACR clean: human-readability confirmed:missed-context ACR clean: missed-context confirmed:regression-safety ACR clean: regression-safety confirmed:replay-determinism ACR clean: replay-determinism ready All ACR dimensions confirmed - clear to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant