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 |
|---|---|---|
| .. | ||
| billing.go | Loading commit data... | |
| channel-billing.go | Loading commit data... | |
| channel-test.go | Loading commit data... | |
| channel.go | Loading commit data... | |
| channel_affinity_cache.go | Loading commit data... | |
| checkin.go | Loading commit data... | |
| codex_oauth.go | Loading commit data... | |
| codex_usage.go | Loading commit data... | |
| console_migrate.go | Loading commit data... | |
| custom_oauth.go | Loading commit data... | |
| deployment.go | Loading commit data... | |
| group.go | Loading commit data... | |
| image.go | Loading commit data... | |
| log.go | Loading commit data... | |
| midjourney.go | Loading commit data... | |
| misc.go | Loading commit data... | |
| missing_models.go | Loading commit data... | |
| model.go | Loading commit data... | |
| model_meta.go | Loading commit data... | |
| model_sync.go | Loading commit data... | |
| oauth.go | Loading commit data... | |
| option.go | Loading commit data... | |
| passkey.go | Loading commit data... | |
| performance.go | Loading commit data... | |
| playground.go | Loading commit data... | |
| prefill_group.go | Loading commit data... | |
| pricing.go | Loading commit data... | |
| ratio_config.go | Loading commit data... | |
| ratio_sync.go | Loading commit data... | |
| redemption.go | Loading commit data... | |
| relay.go | Loading commit data... | |
| secure_verification.go | Loading commit data... | |
| setup.go | Loading commit data... | |
| subscription.go | Loading commit data... | |
| subscription_payment_creem.go | Loading commit data... | |
| subscription_payment_epay.go | Loading commit data... | |
| subscription_payment_stripe.go | Loading commit data... | |
| swag_video.go | Loading commit data... | |
| task.go | Loading commit data... | |
| telegram.go | Loading commit data... | |
| token.go | Loading commit data... | |
| topup.go | Loading commit data... | |
| topup_creem.go | Loading commit data... | |
| topup_stripe.go | Loading commit data... | |
| twofa.go | Loading commit data... | |
| uptime_kuma.go | Loading commit data... | |
| usedata.go | Loading commit data... | |
| user.go | Loading commit data... | |
| vendor_meta.go | Loading commit data... | |
| video_proxy.go | Loading commit data... | |
| video_proxy_gemini.go | Loading commit data... | |
| wechat.go | Loading commit data... |