Scale: multi-replica execution claim, distributed limits, async agent runs, persisted measurement #4

Open
opened 2026-10-12 21:04:08 +00:00 by KofTwentyTwo · 0 comments
KofTwentyTwo commented 2026-10-12 21:04:08 +00:00 (Migrated from github.com)

0.1.0 supports one replica of the Marketing worker. docs/OPERATIONS.md ("Scale and limits") lists the gaps; this issue tracks closing them.

  1. Database-level execution claim. The worker holds an in-JVM lock and re-reads the row before marking it Running. Two replicas can claim the same due execution in the window between read and update. Claim with a conditional update instead (UPDATE marketing_execution SET status = RUNNING, lease_owner = ? WHERE id = ? AND status = SCHEDULED, and check the row count), or with SELECT ... FOR UPDATE SKIP LOCKED. Add a two-worker test.
  2. Distributed rate limits and agent concurrency. maxModelCallsPerMinute and maxConcurrentAgentRuns are in memory, one per JVM. Move them to the database or a shared store, for example a token-bucket row per provider and a run-slot count.
  3. Async agent-run queue. Agent runs execute synchronously inside the record action, bounded by maxRunSeconds; a restart fails them. Queue runs (status QUEUED) and run them on the scheduler with bounded workers. Keep the requester's identity and permissions, either through an automated session for the requesting user or a captured permission set, so tools still read as that user.
  4. Persisted measurement. MeasurementReport loads every event of a campaign on each view. Add a daily rollup table (campaign, stage, event type, raw count, unique actors) maintained when events are written or by a scheduled job, and an importer interface for analytics sources (site analytics, GitHub release downloads).

Each item needs a test, and the README's "implemented / not configured" table must be updated when it is done.

🤖 Generated with Claude Code

0.1.0 supports **one replica** of the Marketing worker. `docs/OPERATIONS.md` ("Scale and limits") lists the gaps; this issue tracks closing them. 1. **Database-level execution claim.** The worker holds an in-JVM lock and re-reads the row before marking it Running. Two replicas can claim the same due execution in the window between read and update. Claim with a conditional update instead (`UPDATE marketing_execution SET status = RUNNING, lease_owner = ? WHERE id = ? AND status = SCHEDULED`, and check the row count), or with `SELECT ... FOR UPDATE SKIP LOCKED`. Add a two-worker test. 2. **Distributed rate limits and agent concurrency.** `maxModelCallsPerMinute` and `maxConcurrentAgentRuns` are in memory, one per JVM. Move them to the database or a shared store, for example a token-bucket row per provider and a run-slot count. 3. **Async agent-run queue.** Agent runs execute synchronously inside the record action, bounded by `maxRunSeconds`; a restart fails them. Queue runs (status QUEUED) and run them on the scheduler with bounded workers. Keep the requester's identity and permissions, either through an automated session for the requesting user or a captured permission set, so tools still read as that user. 4. **Persisted measurement.** `MeasurementReport` loads every event of a campaign on each view. Add a daily rollup table (campaign, stage, event type, raw count, unique actors) maintained when events are written or by a scheduled job, and an importer interface for analytics sources (site analytics, GitHub release downloads). Each item needs a test, and the README's "implemented / not configured" table must be updated when it is done. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: QRun-IO/qbit-marketing#4