Replace all bare task.Update() (DB.Save) calls with UpdateWithStatus(), which adds a WHERE status = ? guard to prevent concurrent processes from overwriting each other's state transitions. Key changes: model/task.go: - Add taskSnapshot struct with Equal() method for change detection - Add Snapshot() method to capture pre-update state - Add UpdateWithStatus(fromStatus) using DB.Where().Save() for CAS semantics with full-struct save (no explicit field listing needed) model/midjourney.go: - Add UpdateWithStatus(fromStatus string) with same CAS pattern service/task_polling.go (updateVideoSingleTask): - Snapshot before processing upstream response; skip DB write if unchanged - Terminal transitions (SUCCESS/FAILURE) use UpdateWithStatus CAS: billing/refund only executes if this process wins the transition - Non-terminal updates also use UpdateWithStatus to prevent overwriting a concurrent terminal transition back to IN_PROGRESS - Defer settleTaskBillingOnComplete to after CAS check (shouldSettle flag) relay/relay_task.go (tryRealtimeFetch): - Add snapshot + change detection; use UpdateWithStatus for CAS safety controller/midjourney.go (UpdateMidjourneyTaskBulk): - Capture preStatus before mutations; use UpdateWithStatus CAS - Gate refund (IncreaseUserQuota) on CAS success (won && shouldReturnQuota) This prevents the multi-instance race condition where: 1. Instance A reads task (IN_PROGRESS), fetches upstream (still IN_PROGRESS) 2. Instance B reads same task, fetches upstream (now SUCCESS), writes SUCCESS 3. Instance A's bare Save() overwrites SUCCESS back to IN_PROGRESS
| Name |
Last commit
|
Last Update |
|---|---|---|
| .. | ||
| openaicompat | Loading commit data... | |
| passkey | Loading commit data... | |
| audio.go | Loading commit data... | |
| billing.go | Loading commit data... | |
| billing_session.go | Loading commit data... | |
| channel.go | Loading commit data... | |
| channel_affinity.go | Loading commit data... | |
| channel_select.go | Loading commit data... | |
| codex_credential_refresh.go | Loading commit data... | |
| codex_credential_refresh_task.go | Loading commit data... | |
| codex_oauth.go | Loading commit data... | |
| codex_wham_usage.go | Loading commit data... | |
| convert.go | Loading commit data... | |
| download.go | Loading commit data... | |
| epay.go | Loading commit data... | |
| error.go | Loading commit data... | |
| error_test.go | Loading commit data... | |
| file_decoder.go | Loading commit data... | |
| file_service.go | Loading commit data... | |
| funding_source.go | Loading commit data... | |
| group.go | Loading commit data... | |
| http.go | Loading commit data... | |
| http_client.go | Loading commit data... | |
| image.go | Loading commit data... | |
| log_info_generate.go | Loading commit data... | |
| midjourney.go | Loading commit data... | |
| notify-limit.go | Loading commit data... | |
| openai_chat_responses_compat.go | Loading commit data... | |
| openai_chat_responses_mode.go | Loading commit data... | |
| quota.go | Loading commit data... | |
| sensitive.go | Loading commit data... | |
| str.go | Loading commit data... | |
| subscription_reset_task.go | Loading commit data... | |
| task.go | Loading commit data... | |
| task_billing.go | Loading commit data... | |
| task_polling.go | Loading commit data... | |
| token_counter.go | Loading commit data... | |
| token_estimator.go | Loading commit data... | |
| tokenizer.go | Loading commit data... | |
| usage_helpr.go | Loading commit data... | |
| user_notify.go | Loading commit data... | |
| violation_fee.go | Loading commit data... | |
| webhook.go | Loading commit data... |