Skip to content

Restart flows via empty-message pokes; restarts no longer pull messages#184

Merged
stidsborg merged 5 commits into
mainfrom
worktree-empty-message-restart
Jul 5, 2026
Merged

Restart flows via empty-message pokes; restarts no longer pull messages#184
stidsborg merged 5 commits into
mainfrom
worktree-empty-message-restart

Conversation

@stidsborg

Copy link
Copy Markdown
Owner

Summary

  • An empty StoredMessage (zero-length content and type) acts as a pure restart-poke: it restarts a not-live flow, is never delivered, and is deleted once the restart it forced has happened. Live flows reopen the poke's position instead of deleting it so the restart guarantee survives a concurrent suspend.
  • Restarts no longer pull messages from the store - message fetching is the MessageWatchdog's sole responsibility:
    • IFunctionStore.RestartExecution returns StoredFlowWithEffects (no messages); the with-messages batch RestartExecutions, StoredFlowWithEffectsAndMessages and the RestartFunction delegate are removed across all stores.
    • The control-panel restart claims the flow, releases its parked positions and notifies the MessageWatchdog so pending messages reach the restarted flow promptly.
  • Completed flows' undeliverable positions are parked per flow in MessageClearer (kept in the ignore-set, so no re-fetch churn) and released again when the flow is explicitly re-invoked. FlowsManager parks before re-reading the flow status (park-then-check): paired with the restart's claim-then-reopen ordering, whichever side acts second sees the other's write - closing a race that otherwise strands positions in the ignore-set forever.
  • ExistingMessages.Append/Replace stamp messages with the publisher's replica id (was ReplicaId.Empty) so the watchdog routes them.
  • QueueManager unwind also reopens delivered-but-not-yet-deleted positions, since restarts no longer hand messages over.

Testing

  • Core in-memory suite: 509/509 passed
  • MariaDB: 366/366, PostgreSQL: 366/366, SQL Server: 366/366

🤖 Generated with Claude Code

stidsborg added 5 commits July 4, 2026 10:42
…ole message-fetch path

RestartExecution returns effects only; the with-messages RestartExecutions,
StoredFlowWithEffectsAndMessages and the RestartFunction delegate are removed.
Completed flows' undeliverable positions are parked per flow (park-then-check
ordering to avoid stranding them when a concurrent explicit restart reopens
parked positions) and released again on explicit re-invocation. ExistingMessages
stamps appended messages with the publisher replica so the watchdog routes them;
QueueManager reopens delivered-but-not-deleted positions on unwind.
… parking positions

A message fetched for a completed flow is moved into the flow's reserved
pending-messages effect entry (serializer-independent BinaryPacker encoding)
and its row deleted - any later re-invocation, on any replica and via any
restart path, receives it from the effect snapshot the restart hands over.
The QueueManager stages the entry at initialization (deduped by position and
idempotency key) and prunes it atomically with each delivery's capture.

The effect write demands the flow is unowned (owner IS NULL) so it cannot
interleave with a claim; rows are deleted only while the flow is observed
still completed afterwards, otherwise the positions are reopened and normal
delivery takes over. The inline uses the store's current rows, not the
fetched copies, so concurrent control-panel Replace/Clear/Remove edits win.

PostgreSQL now stores effects in a column on the flows table (fillfactor 80)
matching MariaDB/SqlServer, gaining the owner-guarded effect write it lacked
and making claim + effect snapshot a single atomic UPDATE..RETURNING; the
separate effects table, its unused version machinery and the orphaned
ReadMessagesForMultipleStores reader are removed. The in-memory store gains
the unowned-flow guard. ExistingMessages surfaces and edits the union of
both message carriers. The per-replica parked-positions state is deleted.
@stidsborg stidsborg merged commit 961b95a into main Jul 5, 2026
8 checks passed
@stidsborg stidsborg deleted the worktree-empty-message-restart branch July 5, 2026 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant