Skip to content

Caller-supplied workflow reservation can miss a committed instance under MySQL REPEATABLE READ #514

Description

@rmcdaniel

Problem

With MySQL REPEATABLE READ, WorkflowStub::make(ExampleWorkflow::class, $callerSuppliedId) can throw ModelNotFoundException for an instance that another transaction has already committed.

Observed with the published Workflow 2.0.14 package, PHP 8.4.25 and MySQL 8.4.5. Reproduced using separate PHP processes/connections, not an in-memory model comparison.

Reproduction

  1. Connection B begins a transaction and executes a normal SELECT, establishing a REPEATABLE READ snapshot before the workflow instance exists.
  2. Connection A reserves the caller-supplied workflow ID, starts its run, and commits.
  3. Without ending its transaction, B calls WorkflowStub::make for the same class and ID, intending to use DuplicateStartPolicy::ReturnExistingActive.
  4. B's insertOrIgnore sees the existing unique ID. The following nonlocking findOrFail still uses B's older snapshot and cannot see that row.

The exception occurs in src/V2/WorkflowStub.php::reserveCallerSuppliedInstance(), before attemptStart() can apply the duplicate-start policy.

Expected

Reservation resolves the already-committed identity, then the normal type and duplicate-start policies apply. No extra instance, run, or task is created; incompatible types must still be rejected.

Scope And Acceptance

  • Use a current database read where reservation reconciles the unique-ID conflict; do not globally lower isolation or bypass workflow identity validation.
  • Add a native-MySQL, separate-connection regression with a pre-existing snapshot and a concurrent committed reservation/start.
  • Cover duplicate start, competing workflow types, and rollback behavior; SQLite alone cannot prove this behavior.
  • Keep the fix focused on caller-ID reservation. This is scheduled normal-priority engine work, not a request for a new orchestration layer.

A consuming application can avoid repeating reservation by reading its already-accepted workflow identity under its existing transaction lock. That workaround does not fix this public API edge case.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:defectA public product behavior is incorrectpriority:P2Normal-priority product work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions