fix: resolve SedonaDB thread pool leak on sql timeout - #1663
Conversation
📝 WalkthroughWalkthrough
ChangesSedona SQL cleanup
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔍 Cloudflare PR preview
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/geolibre_server/geolibre_server/sedona_ops.py`:
- Around line 228-231: Update the cleanup exception handler around close() in
the connection path to log a warning containing the caught exception details
while keeping cleanup non-throwing. Use the existing logger, if available, and
ensure the warning does not include SQL text or query contents.
- Line 225: Replace the ignored variadic argument annotations with object in
_close_connection and _slow_sql, including both *args and **kwargs where
present, while keeping the ignored arguments visible. Update
backend/geolibre_server/tests/test_sedona_ops.py at lines 33-33 similarly; no
other behavior changes are needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d2353a13-4fdd-4641-b2bc-bcb8ea4f55f9
📒 Files selected for processing (2)
backend/geolibre_server/geolibre_server/sedona_ops.pybackend/geolibre_server/tests/test_sedona_ops.py
|
/claude-review |
Code reviewBugs
Security
Performance
Quality
CLAUDE.md
|
🔍 GitHub Pages PR preview
|
- Drop the no-op `future.cancel()` on timeout. The pool has a single worker and a single task, so the query is always already running by then and `cancel()` would return False. Replaced with a comment explaining why the statement runs to completion and cleanup is deferred instead. - Log a warning (without the SQL text) when `connection.close()` fails, so a close that strands Rust-backed resources is not silently swallowed. - Annotate the ignored variadics on `_close_connection` / `_slow_sql` as `object` rather than `Any` — nothing meaningful flows through them. - Poll for the deferred close in `test_sql_timeout_graceful_shutdown` instead of a fixed 0.4s sleep, so scheduling jitter on a loaded CI host cannot make the assertion flaky.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/geolibre_server/geolibre_server/sedona_ops.py (1)
243-246: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy liftBound the lifetime of timed-out Sedona SQL work.
runner.result()times out, but the submitted_execute()task continues to run and the connection remains open. This call is exposed fromPOST /sql/run, so repeated long-running queries can accumulate live threads and Rust-backed connection resources. Enforce a global limit on in-flight timed-out calls, add backpressure, or bound process/subprocess lifetime in the sidecar.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/geolibre_server/geolibre_server/sedona_ops.py` around lines 243 - 246, Update the timeout handling around _execute and _close_connection so a timed-out Sedona SQL task cannot accumulate indefinitely: enforce a global bound on in-flight timed-out calls with backpressure, or otherwise bound the worker/sidecar lifetime and ensure the connection is released when that bound is reached. Preserve normal completion cleanup while making repeated POST /sql/run timeouts consume only the configured finite capacity.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@backend/geolibre_server/geolibre_server/sedona_ops.py`:
- Around line 243-246: Update the timeout handling around _execute and
_close_connection so a timed-out Sedona SQL task cannot accumulate indefinitely:
enforce a global bound on in-flight timed-out calls with backpressure, or
otherwise bound the worker/sidecar lifetime and ensure the connection is
released when that bound is reached. Preserve normal completion cleanup while
making repeated POST /sql/run timeouts consume only the configured finite
capacity.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ac784d38-1fe9-4917-9c2d-33b8588952d2
📒 Files selected for processing (2)
backend/geolibre_server/geolibre_server/sedona_ops.pybackend/geolibre_server/tests/test_sedona_ops.py
Description
This PR fixes a severe concurrency race condition in
sedona_ops.pywhere long-running sql queries could cause a rust panic and hardcrash the python server worker.The Bug:
When a spatial sql query exceeds the
_STATEMENT_TIMEOUT_MSlimit, theThreadPoolExecutorraisesTimeoutError. Previously , the main thread would catch this and instantly force close the SedonaDB database connection. However, the background rust thread (DataFusion/Sedona) was still executing the query. dropping the connection context out from under the actively running native thread caused memory leaks and fatal panics that crashed the entire Python worker.The Fix:
future.add_done_callbackis attached to the running thread. The database connection is now kept alive just long enough for the runaway Rust thread to finish its computation safely behind the scenes, after which it cleans itself up.ruff(ANN202/ARG001).Testing
test_sql_timeout_graceful_shutdownto explicitly simulate a slow query that breaches the timeout. It asserts thatSqlTimeoutis raised properly, and strictly verifies thatconnection.close()is not called instantly, but is deferred until the background thread completes.Summary by CodeRabbit
Bug Fixes
Tests