Skip to content

fix(llm): cancel queued chunks when on_chunk_done raises - #5187

Open
MaxWang007 wants to merge 1 commit into
Graphify-Labs:v8from
MaxWang007:fix/5184-cancel-on-callback-error
Open

MaxWang007 wants to merge 1 commit into
Graphify-Labs:v8from
MaxWang007:fix/5184-cancel-on-callback-error

Conversation

@MaxWang007

Copy link
Copy Markdown
Contributor

What does this PR do?

extract_corpus_parallel submits every chunk before it runs on_chunk_done. When that callback raises, the executor still waits for the whole queue, so the remaining model calls keep going (#5184).

Cancel futures that have not started, let calls that are already running finish, and re-raise the original callback exception.

Fixes #5184

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Tests or CI
  • Refactor
  • Security fix

Verification & Invariants

A callback failure must not start model calls that are still queued. Work already in flight may finish. The exception that leaves the function is the callback's exception.

A worker can still pick up one more chunk in the gap after a call returns and before the callback raises. That call has started, so it is not cancelled. Chunks still sitting in the queue are. The one-worker path already stops at the callback, because it never pre-submits.

  • Read the CONTRIBUTING.md guide.
  • Reproduced the issue and identified the invariant.
  • Made the smallest fix necessary.
  • Added a regression test (if bug fix) or isolated boundary test.
  • Kept the PR description synchronized with the final implementation.
  • Documented any limitations / unsupported cases explicitly.

How was this tested?

Fake model, no network. The new test failed on v8 (52cb282, all six chunks ran) and passes with this change. Repeated it 8 times.

uv run pytest tests/test_chunking.py::test_corpus_parallel_cancels_queued_chunks_when_callback_raises -q
uv run pytest tests/test_chunking.py tests/test_llm_backends.py -q
uv run ruff check graphify/llm.py tests/test_chunking.py

229 passed, 1 skipped in the chunking and LLM backend suites.

Graphify-specific checklist

  • I updated generated skill artifacts (uv run python -m tools.skillgen --bless) when changing their source fragments.
  • I confirmed that AST/structural extraction remains deterministic (no ambient state dependencies like ENV variables).
  • I reviewed changes for security implications (no unsafe interpolation into shell/Python).
  • I confirmed no API keys or local-only graph data are included.
  • (If applicable) I disclosed AI authorship in my commit messages.

extract_corpus_parallel submits every chunk before handling callbacks.
The executor then waits for that whole queue, so a callback error still
runs the model calls that have not started. Cancel those futures, let
in-flight calls finish, and re-raise the original exception (Graphify-Labs#5184).

Co-Authored-By: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown

Thanks for the pull request, @MaxWang007. A maintainer will review it soon.

Want to talk it through while it is in review? Come join us on our Discord server. For longer-form discussion there is also GitHub Discussions.

A couple of things that speed up review: make sure the test suite passes on Python 3.10 and 3.13, and that the change keeps extraction deterministic.

@github-actions github-actions Bot added the contributor Pull request from a returning community contributor label Nov 13, 2026

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

No issues found by static checks — no coupling regressions or blocking issues in the code graph. That is not the same as safe to merge: see what was not checked.

Not checked: tests were not run; formal verification proved 0 of 1 changed function(s) (1 not verified).

Formal verification. PR-changed functions: 0/1 verified (0 proven, 0 may-equivalent, 0 distinguished) · 1 not verified (1 unsupported).

Not verified on this run: extract\_corpus\_parallel (unsupported).


Graphify review — findings

Cancels still-queued chunks in extract_corpus_parallel when handling a finished chunk raises an Exception, such as an on_chunk_done callback failure, so queued model calls no longer run after the callback has failed. Chunks already running finish while the pool drains, and the original exception propagates unchanged. A new test uses a two-worker barrier to show the callback's error surfaces and that chunks queued behind the in-flight pair are never called.

No blocking issues surfaced. 2 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1277 functions depend on the 308 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: extract_corpus_parallel() — 32 callers, 15 callees

Verification — 1277 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 901 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

66 of 564 test file(s) selected (12%) via static blast radius.

  • tests/test_5072_splittable_under_cap_retry.py — impact
  • tests/test_backend_env_isolation.py — impact
  • tests/test_backend_extras.py — impact
  • tests/test_backend_opt_in.py — impact
  • tests/test_build.py — impact
  • tests/test_build_located_semantic_identity.py — impact
  • tests/test_build_merge_dedup_scope.py — impact
  • tests/test_build_merge_ghost_fold_4955.py — impact
  • tests/test_build_merge_hyperedges_and_prune.py — impact
  • tests/test_build_merge_shrink_guard.py — impact
  • tests/test_c_include_resolution.py — impact
  • tests/test_carried_hyperedge_remap.py — impact
  • tests/test_charmap_encoding.py — impact
  • tests/test_chunking.py — impact, changed-test
  • tests/test_claude_cli_backend.py — impact
  • tests/test_corrupt_graph_json.py — impact
  • tests/test_cpp_forward_declarations.py — impact
  • tests/test_cross_extension_reexport_self_cycle.py — impact
  • tests/test_dedup.py — impact
  • tests/test_dedup_remaps_hyperedges.py — impact
  • tests/test_dedup_shrink_refuses_force_write.py — impact
  • tests/test_dedup_survivor_richness.py — impact
  • tests/test_evidence_binding.py — impact
  • tests/test_ext_tagged_id_clash.py — impact
  • tests/test_file_id_collision_4854.py — impact
  • tests/test_file_slice.py — impact
  • tests/test_file_truncation_warning.py — impact
  • tests/test_global_graph.py — impact
  • tests/test_go_qualified_resolution.py — impact
  • tests/test_hyperedge_member_shapes.py — impact
  • tests/test_image_vision.py — impact
  • tests/test_injection_sentinel_coverage.py — impact
  • tests/test_issue_3472_source_file_collision.py — impact
  • tests/test_js_member_collisions.py — impact
  • tests/test_label_retry.py — impact
  • tests/test_labeling.py — impact
  • tests/test_llm_backends.py — impact
  • tests/test_llm_null_token_counts.py — impact
  • tests/test_llm_parser.py — impact
  • tests/test_llm_parser_reasoning.py — impact
  • tests/test_merge_sweeps_reextract_orphans.py — impact
  • tests/test_no_dedup_flag.py — impact
  • tests/test_non_string_node_ids.py — impact
  • tests/test_ollama.py — impact
  • tests/test_ollama_ctx_sizing.py — impact
  • tests/test_ollama_live.py — impact
  • tests/test_ollama_native_chat.py — impact
  • tests/test_ollama_retry_cap.py — impact
  • tests/test_oversized_document_slicing.py — impact
  • tests/test_partial_cache.py — impact
  • … and 16 more

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Formal verification

Could not verify: Could not verify extract\_corpus\_parallel.

The verifier did not have enough to check extract\_corpus\_parallel, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: no capturable inputs from the test suite; property tier: parameter `on_chunk_done` is annotated `Callable | None` — outside the synthesizable primitive/collection set

· 1 more finding(s) on lines outside this diff (see the check run).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor Pull request from a returning community contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

extract_corpus_parallel continues queued model calls after on_chunk_done raises

1 participant