Skip to content

fix: chembl_bridge()/dti_pairs() conflict under concurrent calls - #2

Merged
aaronkanzer merged 1 commit into
mainfrom
fix/concurrent-catalog-conflict
Aug 29, 2026
Merged

aaronkanzer merged 1 commit into
mainfrom
fix/concurrent-catalog-conflict

Conversation

@aaronkanzer

Copy link
Copy Markdown
Member

Summary

  • Regression from fix: reuse the DuckDB connection across calls, fix a cache download race #1 (0.2.2's connection reuse): chembl_bridge() and dti_pairs() each registered their result as a named CREATE OR REPLACE VIEW, which is catalog-mutating DDL. Now that connect() returns a cursor on a shared base connection per release, that DDL is shared mutable state, and two calls racing it from different threads conflict. Reproduced directly: a 24-thread stress run mixing both functions failed 46/48 calls with DuckDB's Catalog write-write conflict on create.
  • Fixed by referencing the parquet file inline via read_parquet() directly in the query instead of registering a named view first, so there's no catalog write to race on.
  • Added regression tests in both modules; verified with the original repro (0/48 errors now) and a broader 64-call mix of every public function running concurrently from a cold start (0 errors).
  • Bumped to 0.2.3.

Test plan

  • pytest -q — 40 passed
  • mypy src/scigantic_bindingdb (strict) — clean
  • Reproduced the pre-fix conflict (46/48 failures) and confirmed it's gone post-fix (0/48), plus a broader mixed-function concurrency stress run (0/64 errors)

🤖 Generated with Claude Code

https://claude.ai/code/session_01L4ztUhMgoMFRicB8uiYx76

Regression from 0.2.2's connection reuse (connect() now returns a cursor
on a shared base connection per release instead of a fresh
duckdb.connect()): chembl_bridge() and dti_pairs() each register their
result as a named CREATE OR REPLACE VIEW, catalog-mutating DDL that's now
shared, mutable state on that connection. Two calls racing that DDL from
different threads collide. Reproduced directly: a 24-thread stress run
mixing chembl_bridge() and dti_pairs() calls failed 46/48 of the time with
DuckDB's "Catalog write-write conflict on create".

Fixed by referencing the parquet file inline via read_parquet() in the
query itself instead of registering a named view first: no catalog write,
nothing to conflict on. Verified with the same stress run (0/48 errors)
and a broader 64-call mix of every function in the package running
concurrently from a cold start (0 errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4ztUhMgoMFRicB8uiYx76
@aaronkanzer
aaronkanzer merged commit ac9ac2a into main Aug 29, 2026
6 checks passed
@aaronkanzer
aaronkanzer deleted the fix/concurrent-catalog-conflict branch August 29, 2026 14:59
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.

1 participant