mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-26 23:50:17 +00:00
fix(jobs): make completed->completed transition idempotent to prevent race errors (#1068)
* fix(jobs): make completed->completed transition idempotent to prevent race errors Both execution_loop and the worker wrapper in execute() can race to call mark_completed(). Previously the second call hit "Cannot transition from completed to completed" and errored the job despite successful completion. This narrowly allows only the Completed->Completed self-transition as idempotent (early return with debug log, no duplicate history entry). All other self-transitions remain rejected to preserve state machine strictness. Co-Authored-By: Claude Opus 4.6 <[email protected]> * style: fix assert! formatting in idempotent completion test Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
9e41b8acea
commit
596d17f04b
+14
-3
@@ -1591,7 +1591,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mark_completed_twice_returns_error() {
|
||||
async fn test_mark_completed_twice_is_idempotent() {
|
||||
let worker = make_worker(vec![]).await;
|
||||
|
||||
worker
|
||||
@@ -1612,11 +1612,22 @@ mod tests {
|
||||
.unwrap();
|
||||
assert_eq!(ctx.state, JobState::Completed);
|
||||
|
||||
// Second mark_completed should succeed (idempotent) rather than
|
||||
// erroring, matching the fix for the execution_loop / worker wrapper
|
||||
// race condition.
|
||||
let result = worker.mark_completed().await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Completed → Completed transition should be rejected by state machine"
|
||||
result.is_ok(),
|
||||
"Completed -> Completed transition should be idempotent"
|
||||
);
|
||||
|
||||
// State should still be Completed
|
||||
let ctx = worker
|
||||
.context_manager()
|
||||
.get_context(worker.job_id)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(ctx.state, JobState::Completed);
|
||||
}
|
||||
|
||||
/// Build a Worker with the given approval context.
|
||||
|
||||
Reference in New Issue
Block a user