Repository navigation
Do not advance the source checkpoint when a batch is truncated (#1212) - #1246
rollroyces wants to merge 1 commit into
Conversation
…ethe#1212) Signed-off-by: Royce Lam <roycelam@umich.edu>
WaylandYang
left a comment
There was a problem hiding this comment.
Thank you for picking up #1212. Both CI failures are mechanical. cargo fmt wants the ResponseTemplate::new(200).set_body_json(...) chain in source_checkpoint_tests.rs on one line. The test fails with a foreign-key error because it calls start_run for the source before the sources row exists; insert the source first.
The bigger problem is that keeping the old since does not get past the cap. The next run gets the same response, takes the same first 200 items (now all Unchanged), and never reaches item 201. The source then reports failed on every run from then on: the window only grows while the checkpoint stays put, so it never recovers, and anything new that the endpoint sorts after position 200 is blocked too. Each of those runs also raises a SOURCE_SYNC_FAILED error alert, and after 50 of them the keep-50 pruning in finish_run deletes the last ok run, so since falls back to None. That is worse than today, where only part of one window is lost. The ADR draft in #1213 lists this exact approach as rejected for the same reason.
For custom, the fix discussed in #1212 is small and fits this PR: walk the whole response (it is already complete) and count only Created/Updated against MAX_NEW_PER_SYNC. Mark the run truncated only when you stop with items left. Each retry then moves forward, and the run ends ok once everything is in. Please also extend the test to sync twice and assert that the 201st item arrives and the second run is ok; as written, the test would pass with the stall. Two smaller things: sync_custom never sets stats.discovered, so the message reads "(0 > 200)"; and whether a capped batch should raise an error alert at all is still open in #1212.
GitHub and Jira are not covered (GitHub's reader stops at ten pages without saying so), and their design is still being settled in #1212 and #1213. Please scope this PR to custom and change "Closes #1212" to "Refs #1212". Running cargo fmt and this test locally with UTOPIA_DATABASE_URL set before pushing would have caught both CI failures.
Why
A custom source endpoint can return more than
MAX_NEW_PER_SYNC = 200items in a single response.
sync_customprocesses only the first 200and the run still finishes with
status = 'ok'. The next round usesthat successful run's
started_atas itssincelower bound; if theremaining items have
last_changebefore that timestamp, an endpointhonoring
sinceexcludes them. Repeated incremental syncs thereforecannot import them unless they change again.
The fix is the same shape as the existing
failed syncpath(
#794): if a successful run actually left a window uncovered, it mustnot look like a success to the incremental cursor. The run still
records the partial work in
created_docs/updated_docsso theaudit trail shows what was imported; the run's
statusisfailedand
last_sync_errorcarries the reason, so the next round picks upwhere this one left off and the remaining items stay reachable.
What changes
crates/utopia-server/src/ingest_sources.rs:SyncStats.truncated: bool— true when a sync function knows itcapped the source's response (
items.len() > MAX_NEW_PER_SYNC).Field default is
false, so existing constructions throughSyncStats::default()and..SyncStats::default()keep working.sync_custom— setsstats.truncated = truewhen the endpointreturns more than 200 items, before the
take(MAX_NEW_PER_SYNC).The overflow items are still dropped; the difference is that the
truncation is now observable.
sync_source— adds a third arm to thematch outcome:Ok(stats) if stats.truncated. It writes the run asfailed(solast_successful_sync_startdoesn't advance), the source asfailed(so the next scheduled run uses the previous successfulsince), the partial work is still increated_docs/updated_docs/last_sync_added, and atracing::warn!tells theoperator why.
What this proposal does not do
source_sync_runs.statusalready has'failed'in its CHECK constraint, and
sources.last_sync_statusaccepts'failed'too.last_successful_sync_startchange.#794alreadyestablished the invariant that only
'ok'runs advance it; thisPR sits on top.
same shape, but Jira already emits a
tracing::warn!fortruncation (
ingest_sources.rs:893) and the maintainer team'spreferred path is per-issue. Adding
truncatedpropagation thereis straightforward if you want it, but the issue's reproduction
exercises
custom, and the smaller surface is easier to review.#1212integration) needs Postgres via
UTOPIA_DATABASE_URLand skipscleanly without it, like the existing
source_checkpoint_tests.rs.Verification
cargo check -p utopia-server --bin utopia-serverdid not finishin the local sandbox (the dev-deps cold rebuild chain on the
external FUSE mount). Recommend running on a workstation with a
normal filesystem before merge.
Tracking