Skip to content

v0.8.45: tune autovacuum, increase indexing worker memory - #7964

Merged
waleedlatif1 merged 9 commits into
mainfrom
staging
Sep 18, 2026
Merged

waleedlatif1 merged 9 commits into
mainfrom
staging

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

icecrasher321 and others added 2 commits September 17, 2026 22:52
* chore(db): tune document autovacuum for connector sync churn

Connector syncs update this table in bursts that outrun autovacuum at the
default 20% scale factor, which on a table of this size only triggers once dead
rows are already substantial. Sustained bloat stops index-only scans trusting
the visibility map, so the knowledge base listing's token aggregate degrades
into per-row heap fetches and can exceed its statement timeout.

The factors are less aggressive than 0357's on purpose. That one is a small
queue table, while this is one of the largest here and shares a small autovacuum
worker pool with many other large tables, so triggering too eagerly would risk
holding a worker continuously and starving its peers. Cost limit and cost delay
are left unset so the table stays inside cross-worker I/O balancing.

* chore(docs): keep production scale out of published text

Comments describing measured behaviour carried absolute production sizing —
index byte sizes, chunk and row totals — which the repo's publishing rules
exclude and which a public reader does not need. The measurements that justify
each decision stay; only the figures that size production are replaced.

The ship scrub missed these because its grep matched identities and IDs but
never numbers, and because code and migration comments do not feel like
publishing even though they are. It now states the distinction explicitly and
greps the diff for byte sizes, k/M-scale entity counts, and seven-figure totals,
while deliberately still allowing ordinary engineering numbers.
@vercel

vercel Bot commented Sep 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Sep 18, 2026 3:57pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge, with the worker preset, migration behavior, and generated metadata all consistent with established repository patterns.

Summary

This PR increases memory available to workspace-file indexing and tunes per-table autovacuum thresholds for connector-driven document churn.

  • Moves the file-search indexing task from medium-1x to medium-2x and updates its test and operational documentation.
  • Sets lower vacuum and analyze scale factors on the document table.
  • Adds internally consistent Drizzle migration metadata.
  • Scrubs absolute production-scale details from several comments and strengthens publishing guidance.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Workspace file indexing request] --> B[Trigger.dev indexing task]
    B --> C[medium-2x worker]
    C --> D[Parse and chunk file]
    D --> E[Publish searchable index]

    F[Connector synchronization] --> G[Document updates]
    G --> H[Dead tuples and changed rows]
    H --> I[Lower autovacuum thresholds]
    I --> J[Earlier vacuum and analyze]
    J --> K[Improved visibility and planner statistics]
Loading

Reviews (1) · Last reviewed commit: "chore(db): tune document autovacuum for ..."

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 9 files

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Fix all with cubic | Re-trigger cubic

Comment thread .agents/skills/ship/SKILL.md
…on (#7966)

* fix(knowledge): store connector sync schedules at millisecond precision

The scheduler round-trips next_member_sync_at through a JavaScript Date and
claims the run by matching the value back exactly. Date carries milliseconds
while PostgreSQL stored microseconds, so a schedule written in SQL rather than
by the application became unmatchable the moment it landed on a fractional
millisecond: the connector stayed permanently due, every claim was refused, and
its members never synced.

Narrow both connector schedule columns to timestamp(3) so the two ends compare
the same value. The rewrite also rounds the stored values, so an already-wedged
row recovers on the next scheduler tick.

Also stop the claim diagnosis from asserting a queued run it cannot see — it now
reads the lock token and says so plainly when no condition explains the refusal,
which is what let this hide as ordinary contention.

* test(knowledge): pin the schedule rewrite's repair of already-stored rows

Scope the column-precision query to the test schema. It matched on table name
alone, so in CI — where the database already holds the migrated public table —
it saw four columns instead of two and failed. A local run passed because the
throwaway schema was the only place that table existed.

Write the sub-millisecond schedule before applying the migration rather than
after, so the test pins the rewrite rounding an already-wedged row, not just the
narrowed column refusing new ones. Without the migration it now fails on exactly
that claim.
* fix(file-search): stop cleanup starting a batch it cannot fund

The batch loop admitted another batch whenever any budget remained, then passed
that remainder through as the batch's statement timeout, clamped to 1ms. A batch
admitted with a sliver left either runs past the budget it was given or aborts on
its own statement timeout, which the caller reports as a cleanup failure rather
than as work still to do.

Stop once less than one batch's nominal share of the budget remains. The floor is
derived from the budget and the batch cap rather than fixed, so retuning either
cannot leave it admitting batches at more than their share again.

* fix(file-search): measure the cleanup budget after the connection is held

Hoisting the remaining-budget read out of the transaction callback made it
describe the moment the batch was admitted rather than the moment its statements
begin. Time spent waiting for a pooled connection then went unaccounted, and the
batch installed a timeout larger than the budget actually left.

Keep the cheap check before opening a transaction, and re-read once the
connection is in hand so the installed timeout is the budget that remains.
…access batch (#7968)

The search source overview loops over access batches and, for each one, ran the
indexing probe in full. That probe's result is only ever read back as set
membership when projecting `isSyncing`, so a provider type already found cannot
change the answer — every later batch re-paid an EXISTS scan over `document`
carrying the full ACL predicate for nothing.

Mirror the searchable probe's existing guard: skip the indexing probe once every
configured provider type is accounted for, and exclude already-found types from
the query on later batches. Both queries build on the same configured condition
and the probe only adds narrowing predicates, so the resulting set is unchanged.
…iew probes saturate (#7970)

The source overview loops over the access batches the read-access generator
yields. The first batch is free, but every later one costs a connector
discovery query plus a per-connector live source proof over the network.

Both probes in the loop already stop issuing queries once they saturate — the
searchable probe on its first hit, the indexing probe once every configured
provider type is accounted for — but the loop kept pulling batches afterwards,
paying the producer's cost for no probe at all.

Hoist the two probe guards into closures so the loop body and the exit share
one definition of each, and break once neither can change the result. Output is
unchanged; only the work is dropped.
#7971)

* fix(knowledge): recover vector candidates an HNSW post-filter discards

pgvector's HNSW index post-filters by construction, so a visibility predicate
can only discard neighbours the graph walk already committed to. When the
documents a caller may read are a small share of the index, the traversal
returns a handful of candidates instead of its limit.

Rank the permitted set exactly when the traversal comes back underfilled and a
bounded probe says that set is small enough to afford. A traversal that fills
its limit is returned untouched, so a scope the graph serves well pays nothing.

Bound the probe by documents examined rather than chunks accumulated, and give
it its own sub-budget so deciding against a rescue can never cost the leg its
results.

Retune the scan settings so the tuple budget sits an order of magnitude above
the beam, which is what lets the iterative scan iterate at all, and so the
narrower beam lowers the leg's uninterruptible floor.

* test(knowledge): cover the capped step budget

* fix(knowledge): require an enabled chunk when a tag filter decides a document

A document whose only tagged chunk is disabled could be admitted by the probe
and then discarded by ranking, spending the probe's document bound on a
document that can contribute no candidate.

Update the KB block fan-out integration test to the strategy it now exercises:
a scope too small to fill the traversal probes once and rescues once.
@waleedlatif1
waleedlatif1 merged commit 1b96097 into main Sep 18, 2026
67 of 68 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants