Observed defect
With published Workflow 2.0.10, a worker crash followed by a repair pass after both the activity lease and schedule-to-close deadline have expired can re-run the activity and complete the workflow instead of recording a terminal timeout.
Reproduced using separate PHP processes, a persisted SQLite database and a real SIGKILL after a generated external-effect marker was written. No live customer runtime or data was involved.
Reproduction
- Start a workflow with an activity configured with maxAttempts=3, startToCloseTimeout=55 and scheduleToCloseTimeout=600.
- Claim/run the activity, write an idempotent external-effect marker, and kill the PHP worker before recording completion.
- Start a fresh process, advance the test clock beyond the lease and the 600-second overall deadline, and run the normal
workflow:v2:repair-pass.
- Process the repaired database queue.
Observed repair report: one repaired task; one activity-timeout candidate; zero timeouts enforced; reason current_attempt_not_running.
Observed history: a second ActivityStarted, ActivityCompleted, then WorkflowCompleted. No ActivityTimedOut is recorded.
TaskRepair closes the expired attempt before the timeout scan. ActivityTimeoutEnforcer then rejects that expired current attempt, and ActivityTaskClaimer can claim the repaired task without enforcing the existing overall deadline.
This is distinct from #498: the exception class now exists, but this path never creates the timeout event.
Acceptance
- An elapsed schedule-to-close deadline remains authoritative through lease repair and fresh-process recovery.
- No activity handler or later workflow effects run after the deadline in this reproduction.
- Record exactly one terminal timeout and restore it normally during workflow replay.
- Preserve retry behavior before the overall deadline, attempt fencing, lock order and stale-completion rejection.
- Cover the ordinary repair pass and the shared claim/enforcement paths used by embedded workers and Server.
- Publish the fix and verify its affected consumers with published artifacts.
Observed defect
With published Workflow 2.0.10, a worker crash followed by a repair pass after both the activity lease and schedule-to-close deadline have expired can re-run the activity and complete the workflow instead of recording a terminal timeout.
Reproduced using separate PHP processes, a persisted SQLite database and a real SIGKILL after a generated external-effect marker was written. No live customer runtime or data was involved.
Reproduction
workflow:v2:repair-pass.Observed repair report: one repaired task; one activity-timeout candidate; zero timeouts enforced; reason
current_attempt_not_running.Observed history: a second ActivityStarted, ActivityCompleted, then WorkflowCompleted. No ActivityTimedOut is recorded.
TaskRepair closes the expired attempt before the timeout scan. ActivityTimeoutEnforcer then rejects that expired current attempt, and ActivityTaskClaimer can claim the repaired task without enforcing the existing overall deadline.
This is distinct from #498: the exception class now exists, but this path never creates the timeout event.
Acceptance