Skip to content

Prevent attempting to suspend multiple times in the same run#82

Merged
virajmehta merged 2 commits intomainfrom
aaron/prevent-double-suspend
Mar 13, 2026
Merged

Prevent attempting to suspend multiple times in the same run#82
virajmehta merged 2 commits intomainfrom
aaron/prevent-double-suspend

Conversation

@Aaron1011
Copy link
Member

@Aaron1011 Aaron1011 commented Mar 13, 2026

The durable sql itself already checks that a task is currnetly running when we try to suspend it, which makes it
very difficult to write tests for. However, checking in the durable sql is insufficient, since we might have an execution that looks like:

  • Tokio task A - calls await_event("foo"), and doesn't propagate the ControlFlow::Suspend error.
  • Tokio task B (possibly in another process) - calls emit_event("foo")
  • Tokio task C - picks up the now-ready task that was previously suspended
  • Tokio task A - calls await_event("bar"), which succeeds, since the task is now running.

By adding a check rust-side, we can be sure that we catch incorrect usage of durable


Note

Medium Risk
Introduces new validation that turns repeated suspend attempts into TaskError::Validation and changes the ControlFlow::Suspend variant shape, which may break pattern matches and alter runtime behavior for tasks that previously (incorrectly) suppressed suspend errors.

Overview
Prevents tasks from suspending more than once per execution by tracking a has_suspended flag on TaskContext and rejecting subsequent suspend attempts with a validation error.

Changes ControlFlow::Suspend to carry an internal SuspendMarker, forcing suspension to be constructed through TaskContext (via SuspendMarker::new(self)), and updates the worker to match ControlFlow::Suspend(_) accordingly.

Written by Cursor Bugbot for commit 5348eee. This will update automatically on new commits. Configure here.

The durable sql itself already checks that a task is currnetly
running when we try to suspend it, which makes it
very difficult to write tests for. However, checking in the durable sql
is insufficient, since we might have an execution that looks like:

* Tokio task A - calls `await_event("foo")`, and doesn't propagate
  the `ControlFlow::Suspend` error.
* Tokio task B (possibly in another process) - calls `emit_event("foo")`
* Tokio task C - picks up the now-ready task that was previously
  suspended
* Tokio task A - calls `await_event("bar")`, which succeeds, since
  the task is now running.

By adding a check rust-side, we can be sure that we catch incorrect
usage of durable
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@virajmehta virajmehta added this pull request to the merge queue Mar 13, 2026
Merged via the queue into main with commit 2bfe262 Mar 13, 2026
2 checks passed
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.

2 participants