Skip to content

Bound background task finalization so one failed task cannot starve index builds #236

Description

@zcourts

Problem

A failed background task can retain the worker semaphore permit indefinitely while recording its failure. On a single-shard topology Anvil currently forces background concurrency to one, so this stalls the entire queue and leaves later typed indexes enabled but unmaterialized.

Worka E2E34 evidence (2026-07-30)

Candidate source: a6b8f719f36190800dcdcceb0c06957270db84bf.

  • Task 110 (AuthzMaterialization) failed at 05:48:25 on an authz-head ValueHash predicate.
  • No failure-recording result, task completion, or later index-build completion was logged.
  • At 05:55:41 recovery found task 110 still running without a valid execution lease and requeued it.
  • All bootstrap index builds had completed by 05:48:29, but none of 11 indexes created for a template workspace around 06:07 materialized.
  • workspace.integration_events_by_time was present, enabled, and version 1, but had no typed segment.
  • Worka queried it with lag_timeout_ms=5000; TypedJsonIndexNotMaterialised stopped the watcher every 15 seconds despite caller reconciliation.

The worker error branch awaits execution_lease_precondition and then fail_task_with_execution_guard inside the spawned task while holding its semaphore permit. Neither await has an outer deadline. Recovery can requeue the task record but cannot release a permit retained by the stuck spawned future.

Single-node serialization compounds the defect: effective_worker_concurrency returns 1 whenever fewer than two shard targets exist, even though durability topology should not serialize unrelated background task execution.

Acceptance criteria

  • Failure and completion persistence have bounded deadlines and cannot retain a worker permit indefinitely.
  • Cancellation leaves a recoverable queue/lease state; recovery can safely reclaim the exact attempt.
  • A deliberately hung failure-finalization operation does not prevent an unrelated queued index build from starting.
  • A failed authz materialization does not starve later index builds.
  • Background concurrency is not reduced to one solely because local durability has one shard target; configured concurrency remains bounded and MVCC/task leases remain authoritative.
  • Focused tests cover timeout, permit release, recovery, and single-node concurrency.
  • Worka's newly created workspace indexes materialize before/within their query lag timeout under the E2E workload.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:mvccMVCC storage, snapshots, conflicts, application, or GCarea:operationsOperator workflow, admission, limits, or runbooksarea:recoveryRestart, replacement, repair, backup, or disaster recoveryarea:testingModel, integration, fault, compatibility, or chaos testingkind:bugConfirmed defect requiring correctionrelease-blockerMust be resolved before the assigned release ships

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions