Skip to content

feat(worker): Crawl as a work item per storage config, with scope routing #281

Closed

Description

@bitbiter-dev

Parent

#276

What to build

Crawling becomes visible, controllable work. Each storage config's crawl is a Crawl work item, due at the crawl interval, with live progress: files found, processed and failed.

Scope routing ships here, because the crawl is its first caller:

  • a per-user worker (WORKER__USER) claims only items scoped to its user's storage configs, plus unscoped items;
  • an all-user worker claims everything.

The Worker's own crawl timer is removed. A crawl on startup now comes from due-ness.

Acceptance criteria

  • Crawl is a periodic kind scoped to one storage config, with DedupKey crawl:<config id>, due after the existing crawl interval (default 4 h).
  • Each worker schedules crawls only for the configs it serves. An inactive config is not scheduled.
  • The claim filters by scope: per-user workers take their own configs and unscoped items, all-user workers take everything. Covered by a contract test on real PostgreSQL with two workers of different scopes.
  • The crawl handler runs today's crawl of that config through the existing ingestion pipeline, with unchanged per-file concurrency, crawl exclusions and failure handling. It reports files found, processed and failed as progress (total unknown while walking).
  • The Worker's own crawl loop and its timer are gone.
  • After a restart that outlasted the crawl interval, the crawl runs straight away.
  • A graceful shutdown mid-crawl releases the item without a stall, and the next run converges. Ingestion is already idempotent by content hash.
  • A test shows that a second run of the crawl handler converges.
  • CLAUDE.md's Worker sections describe crawling as a work item.
  • 100% mutation score outside PostgreSQL-only members, which get ADR 0005 rows.

First caller

The Crawl kind, which is also the first caller of scope routing.

Design

Decided with the maintainer on 2026-10-18 (#276: crawls are work items, scope by storage config, one item at a time per worker). Per-file retry stays with #132.

Activity

  1. added
    needs-triageMaintainer needs to evaluate this issue
    and removed
    ready-for-agentFully specified, ready for an AFK agent
    on Oct 18, 2026
  2. github-actions commented on Oct 18, 2026

    @github-actions

    Moved back to needs-triage: docs/agents/design-process.md ("What every issue carries") requires these parts before ready-for-agent:

    • Design: a "## Design" section or "Design:" field with a link to the approved design note (an #issuecomment link) or an ADR, or "Design: not needed because "

    Add them, then label the issue ready-for-agent again.

  3. bitbiter-dev commented on Oct 18, 2026

    @bitbiter-dev
    OwnerAuthor

    Note from #282

    #282 stops one storage config's failed crawl from taking the Worker down. Worker.CrawlAllAsync now logs the failure and moves on to the next config. One crash path is still open, and this issue should close it when the crawl moves onto the queue:

    • Loading the config list can still stop the host. GetAllActiveAsync / GetActiveByUserIdAsync runs outside the per-config catch. If it throws (the database is unreachable, for example), the exception escapes RecurringWork.RunAsync, faults the BackgroundService, and the default StopHost stops the Worker, which then crash-loops under restart: unless-stopped.

    With the queue, scheduling crawls is the scheduler's job, so a failing query there must not fault the hosted service either. Suggested acceptance line:

    • A failure while scheduling crawls (e.g. the storage-config query throws) is logged, and the scheduler and executor keep running and retry on their next tick. Covered by a test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestneeds-triageMaintainer needs to evaluate this issue

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions