Muse Spark 1.3·续2
Here's a reversible plan — old queue stays source-of-truth until parity is proven. All switches behind flags.
**1. Monitor - lag monitoring:**
Add publish rate, `queue_depth_old`, `log_end_offset - consumer_offset` per partition/fleet, e2e latency, DLQ counts. Rollback trigger: metrics missing/divergent in audit -> stop.
**2. Dual write - old primary:**
Producers sync-write old, best-effort async-write new log with same `job_id`. Compare counts. Rollback trigger: new-write error >0.1% or p99 +10% -> flag off, ignore new log.
**3. Shadow consumers:**
Deploy 3 new fleets reading new log, execute but suppress side-effects, diff vs old. Rollback trigger: mismatch or crash -> disable shadow, fix.
**4. Deduplicate:**
Add `job_id` idempotency table, TTL > retention. New workers dedup; reconcile old vs new processed sets hourly. Rollback trigger: duplicate side-effect or reconcile gap -> stay on old.
**5. Cutover - new primary:**
Flip to new log primary, old as fallback, dual-read + dedup. Move one fleet at a time. Rollback trigger: lag >30s, error-budget burn, or DLQ spike -> flag back to old instantly.
**6. Drain:**
Stop writes to old, drain workers, dark-launch 48h. Rollback trigger: old-queue reappearance -> re-enable.
**Invariant before deleting old queue:** `queue_depth_old=0` for full retention window AND producer refs=0 AND new-log lag ~0 AND 100% reconciled `job_ids` with zero pending dedup keys.
{
"id": "resp_6ac7ad2d29eeea2059184ed9",
"object": "response",
"created_at": 1791470893,
"model": "muse-spark-1.3",
"output": [
{
"type": "reasoning",
"id": "rs_6ac7ad2d29eeea2059184ed9:rs_9a03ef30-1d43-4ddb-92ff-faea1c123a3f",
"summary": [],
"status": "completed"
},
{
"type": "message",
"id": "msg_807b479b-0d11-45d6-9fb5-2e304375c590",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Here's a reversible plan — old queue stays source-of-truth until parity is proven. All switches behind flags.\n\n**1. Monitor - lag monitoring:**\nAdd publish rate, `queue_depth_old`, `log_end_offset - consumer_offset` per partition/fleet, e2e latency, DLQ counts. Rollback trigger: metrics missing/divergent in audit -> stop.\n\n**2. Dual write - old primary:**\nProducers sync-write old, best-effort async-write new log with same `job_id`. Compare counts. Rollback trigger: new-write error >0.1% or p99 +10% -> flag off, ignore new log.\n\n**3. Shadow consumers:**\nDeploy 3 new fleets reading new log, execute but suppress side-effects, diff vs old. Rollback trigger: mismatch or crash -> disable shadow, fix.\n\n**4. Deduplicate:**\nAdd `job_id` idempotency table, TTL > retention. New workers dedup; reconcile old vs new processed sets hourly. Rollback trigger: duplicate side-effect or reconcile gap -> stay on old.\n\n**5. Cutover - new primary:**\nFlip to new log primary, old as fallback, dual-read + dedup. Move one fleet at a time. Rollback trigger: lag >30s, error-budget burn, or DLQ spike -> flag back to old instantly.\n\n**6. Drain:**\nStop writes to old, drain workers, dark-launch 48h. Rollback trigger: old-queue reappearance -> re-enable.\n\n**Invariant before deleting old queue:** `queue_depth_old=0` for full retention window AND producer refs=0 AND new-log lag ~0 AND 100% reconciled `job_ids` with zero pending dedup keys.",
"annotations": [],
"logprobs": []
}
],
"status": "completed"
}
],
"status": "completed",
"usage": {
"input_tokens": 126,
"output_tokens": 2390,
"total_tokens": 2516,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens_details": {
"reasoning_tokens": 2024
}
},
"top_logprobs": 0,
"temperature": 1,
"top_p": 1,
"service_tier": "auto",
"reasoning": {
"effort": "high"
},
"background": false,
"tools": [],
"tool_choice": "auto",
"truncation": "disabled",
"completed_at": 1791470893,
"error": null,
"incomplete_details": null,
"instructions": null,
"parallel_tool_calls": true,
"store": true,
"max_output_tokens": 8192
}
</details>
<details>
<summary>Incident Timeline Analysis — Analyze an outage timeline, identify the likely contributing factors, and propose follow-up actions.</summary>
const response = await env.AI.run(
'meta/muse-spark-1.3',
{
messages: [
{
role: 'user',
content:
'Analyze this incident timeline:\n\n09:00: deploy increases worker concurrency from 20 to 80.\n09:07: queue depth begins rising.\n09:12: database connection utilization reaches 95%.\n09:16: retries increase and queue depth doubles.\n09:25: rollback starts.\n09:31: queue depth returns to normal.\n\nWrite a blameless root-cause summary, distinguish direct cause from contributing factors, and propose four follow-up actions with measurable success criteria.',
},
],
max_completion_tokens: 4096,
},
)
console.log(response)
curl https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/ai/run \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"model": "meta/muse-spark-1.3",
"input": {
"messages": [
{
"role": "user",
"content": "Analyze this incident timeline:\n\n09:00: deploy increases worker concurrency from 20 to 80.\n09:07: queue depth begins rising.\n09:12: database connection utilization reaches 95%.\n09:16: retries increase and queue depth doubles.\n09:25: rollback starts.\n09:31: queue depth returns to normal.\n\nWrite a blameless root-cause summary, distinguish direct cause from contributing factors, and propose four follow-up actions with measurable success criteria."
}
],
"max_completion_tokens": 4096
}
}'
### Blameless Root-Cause Summary
**TL;DR:** A 4x increase in worker concurrency at 09:00 saturated a downstream bottleneck - the database connection pool - which reduced effective throughput, causing queue depth to grow. Retries then amplified the load and created a feedback loop. Rollback removed the overload and service recovered, which strongly implicates the concurrency change as the trigger.
Increasing workers from 20 to 80 would normally *decrease* queue depth. That the queue *rose* 7 minutes after the deploy is a key signal: workers were not processing faster, they were getting slower/blocked waiting on a shared resource.
What we can infer from the timeline alone:
09:00 -> 09:07 deploy precedes queue growth
09:12 -> DB at 95% shows downstream saturation
09:16 -> retries + doubling queue shows amplification
09:25 -> 09:31 rollback -> recovery confirms causal link
This analysis is based on metrics correlation. Trace-level confirmation - worker wait time, DB query latency/timeouts, connection acquire timeouts - would finalize it.
### Direct Cause vs. Contributing Factors
**Direct Cause:**
Worker demand exceeded database serving capacity. 80 concurrent workers contended for a finite pool of DB connections. Once utilization approached saturation (~95%), connection wait time, query latency, and timeouts increased. Throughput fell below arrival rate, so queue depth rose even though there were more workers.
**Contributing Factors - the system allowed this to happen:**
1. **Unsafe config change:** The system permitted a 4x concurrency jump with no validation against downstream DB capacity.
2. **No backpressure / load-shedding:** Workers kept accepting/polling work even when the DB could not keep up, instead of throttling.
3. **Retry amplification:** Retries starting at 09:16 added load to an already saturated DB, doubling queue depth - a classic retry storm without sufficient backoff.
4. **Slow detection and mitigation:** First signal at 09:07, but rollback did not start until 09:25 - 18 minutes of growing impact. There was no early joint alert on queue + DB, no canary, and no auto-rollback.
No individual is at fault. The process lacked guardrails, safe rollout, and resilient defaults.
### 4 Follow-Up Actions
**1. Enforce concurrency-to-DB capacity guardrail**
Cap `worker_concurrency * max_connections_per_worker` to a safe fraction of provisioned DB connections.
*Owner: Platform / DBA*
*Success criteria:* Within 2 weeks, CI blocks any deploy where projected usage >70% of DB max connections. Achieve 100% coverage of worker pools and 0 violations over the next 30 days. Verified by a load test at 80 workers staying <70% DB utilization.
**2. Make retries safe under saturation**
Add bounded retries with exponential backoff + jitter, timeouts, and a circuit-breaker on DB connection timeouts.
*Owner: Backend*
*Success criteria:* In a staging reproduction of 95% DB utilization, retry amplification is <1.2x baseline traffic vs. ~2x seen on 09:16, and p95 job latency does not degrade >20%. Merged and load-tested within 3 weeks.
**3. Require progressive rollout for scaling changes**
Any concurrency increase >20% must go via canary: 5% -> 25% -> 100% with automatic halt/rollback.
*Owner: SRE / Release*
*Success criteria:* Within 1 month, all worker scaling uses canary. Canary auto-halts if queue depth growth >20% over 5-min baseline OR DB utilization >80% for 3 min. Demonstrated in one game day with time-to-halt <10 min.
**4. Add joint alerting + mitigation runbook**
Create a paging alert that correlates leading and lagging signals, not just one metric.
*Owner: On-call / Observability*
*Success criteria:* Within 2 weeks, new alert: `queue depth increasing for 5 min AND DB utilization >80%` pages within 5 min. Runbook for "worker saturation" documented and drill-tested. In next drill: Time-to-detect <5 min, Time-to-start-mitigation <10 min.
{
"id": "resp_6ac7ad5f3c5042d4703149a8",
"object": "response",
"created_at": 1791470943,
"model": "muse-spark-1.3",
"output": [
{
"type": "reasoning",
"id": "rs_6ac7ad5f3c5042d4703149a8:rs_c616723d-3712-4ee3-96ad-72d2a63569fa",
"summary": [],
"status": "completed"
},
{
"type": "message",
"id": "msg_36a2fc5c-fce5-43d7-808a-6603c27b4779",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "### Blameless Root-Cause Summary\n\n**TL;DR:** A 4x increase in worker concurrency at 09:00 saturated a downstream bottleneck - the database connection pool - which reduced effective throughput, causing queue depth to grow. Retries then amplified the load and created a feedback loop. Rollback removed the overload and service recovered, which strongly implicates the concurrency change as the trigger.\n\nIncreasing workers from 20 to 80 would normally *decrease* queue depth. That the queue *rose* 7 minutes after the deploy is a key signal: workers were not processing faster, they were getting slower/blocked waiting on a shared resource.\n\nWhat we can infer from the timeline alone:\n09:00 -> 09:07 deploy precedes queue growth\n09:12 -> DB at 95% shows downstream saturation\n09:16 -> retries + doubling queue shows amplification\n09:25 -> 09:31 rollback -> recovery confirms causal link\n\nThis analysis is based on metrics correlation. Trace-level confirmation - worker wait time, DB query latency/timeouts, connection acquire timeouts - would finalize it.\n\n### Direct Cause vs. Contributing Factors\n\n**Direct Cause:**\nWorker demand exceeded database serving capacity. 80 concurrent workers contended for a finite pool of DB connections. Once utilization approached saturation (~95%), connection wait time, query latency, and timeouts increased. Throughput fell below arrival rate, so queue depth rose even though there were more workers.\n\n**Contributing Factors - the system allowed this to happen:**\n\n1. **Unsafe config change:** The system permitted a 4x concurrency jump with no validation against downstream DB capacity.\n2. **No backpressure / load-shedding:** Workers kept accepting/polling work even when the DB could not keep up, instead of throttling.\n3. **Retry amplification:** Retries starting at 09:16 added load to an already saturated DB, doubling queue depth - a classic retry storm without sufficient backoff.\n4. **Slow detection and mitigation:** First signal at 09:07, but rollback did not start until 09:25 - 18 minutes of growing impact. There was no early joint alert on queue + DB, no canary, and no auto-rollback.\n\nNo individual is at fault. The process lacked guardrails, safe rollout, and resilient defaults.\n\n### 4 Follow-Up Actions\n\n**1. Enforce concurrency-to-DB capacity guardrail**\nCap `worker_concurrency * max_connections_per_worker` to a safe fraction of provisioned DB connections.\n*Owner: Platform / DBA*\n*Success criteria:* Within 2 weeks, CI blocks any deploy where projected usage >70% of DB max connections. Achieve 100% coverage of worker pools and 0 violations over the next 30 days. Verified by a load test at 80 workers staying <70% DB utilization.\n\n**2. Make retries safe under saturation**\nAdd bounded retries with exponential backoff + jitter, timeouts, and a circuit-breaker on DB connection timeouts.\n*Owner: Backend*\n*Success criteria:* In a staging reproduction of 95% DB utilization, retry amplification is <1.2x baseline traffic vs. ~2x seen on 09:16, and p95 job latency does not degrade >20%. Merged and load-tested within 3 weeks.\n\n**3. Require progressive rollout for scaling changes**\nAny concurrency increase >20% must go via canary: 5% -> 25% -> 100% with automatic halt/rollback.\n*Owner: SRE / Release*\n*Success criteria:* Within 1 month, all worker scaling uses canary. Canary auto-halts if queue depth growth >20% over 5-min baseline OR DB utilization >80% for 3 min. Demonstrated in one game day with time-to-halt <10 min.\n\n**4. Add joint alerting + mitigation runbook**\nCreate a paging alert that correlates leading and lagging signals, not just one metric.\n*Owner: On-call / Observability*\n*Success criteria:* Within 2 weeks, new alert: `queue depth increasing for 5 min AND DB utilization >80%` pages within 5 min. Runbook for \"worker saturation\" documented and drill-tested. In next drill: Time-to-detect <5 min, Time-to-start-mitigation <10 min.",
"annotations": [],
"logprobs": []
}
],
"status": "completed"
}
],
"status": "completed",
"usage": {
"input_tokens": 102,
"output_tokens": 2497,
"total_tokens": 2599,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens_details": {
"reasoning_tokens": 1600
}
},
"top_logprobs": 0,
"temperature": 1,
"top_p": 1,
"service_tier": "auto",
"reasoning": {
"effort": "high"
},
"background": false,
"tools": [],
"tool_choice": "auto",
"truncation": "disabled",
"completed_at": 1791470943,
"error": null,
"incomplete_details": null,
"instructions": null,
"parallel_tool_calls": true,
"store": true,
"max_output_tokens": 4096
}
