feat(core): make JobStore connection pooling configurable - #2150
feat(core): make JobStore connection pooling configurable#2150jonthedecepticon wants to merge 1 commit into
Conversation
WalkthroughThe job store engine now accepts SQLAlchemy engine keyword arguments and environment-based pool settings. It validates pool values, gives explicit arguments precedence, forwards settings to sync and async engines, adds tests, and documents the configuration. ChangesJob store pool configuration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant EnvironmentVariables
participant get_db_engine
participant SQLAlchemyEngineFactory
Caller->>get_db_engine: Supply explicit engine kwargs
EnvironmentVariables->>get_db_engine: Provide pool settings
get_db_engine->>get_db_engine: Validate and merge settings
get_db_engine->>SQLAlchemyEngineFactory: Create sync or async engine
SQLAlchemyEngineFactory-->>Caller: Return configured engine
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/async_jobs/job_store.py`:
- Around line 648-650: Update get_db_engine and _pool_kwargs_from_env so each
pool environment variable is parsed only when its corresponding engine_kwargs
key is absent, allowing explicit arguments to bypass malformed environment
values. Preserve explicit-argument precedence and add regression tests covering
malformed overridden pool settings.
- Around line 613-623: Rewrite the complete get_db_engine docstring in Google
style, including a concise first-line summary that ends with a period and
Google-style Args, Returns, Raises, and relevant notes sections for the existing
API behavior. Preserve the documented engine_kwargs details and
environment-variable behavior while removing NumPy-style section syntax.
In `@packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_job_store.py`:
- Around line 734-736: Add the documented ("no", False) case to the
parameterization for the test covering _POOL_PRE_PING_FALSE_VALUES, preserving
the existing true and false value coverage.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: e2993352-5a21-4c09-b135-e04bb8825603
📒 Files selected for processing (3)
docs/source/reference/rest-api/api-server-endpoints.mdpackages/nvidia_nat_core/src/nat/front_ends/fastapi/async_jobs/job_store.pypackages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_job_store.py
30b514d to
f9d1fc0
Compare
|
Thanks, addressed two of the three.
Skipping the Google-style docstring change. |
|
Maintainers: this PR has no labels, so the Label Checker is failing with A vet for |
|
Checked the multi-process argument against The premise holds. # Set environment variabls such that the worker subprocesses will know how to connect to dask and to
# the database
os.environ.update({
"NAT_DASK_SCHEDULER_ADDRESS": self._scheduler_address,
"NAT_JOB_STORE_DB_URL": db_url,
...
})and But that same code undercuts the reason given for not adding a config field. I don't think that makes the environment-variable version wrong — it's the smaller change and it works. It does mean the choice between it and a YAML surface is a maintainer's preference about the config surface, not a constraint, and the PR currently presents it as a constraint. Worth stating plainly so whoever reviews it decides the actual question. One thing outside the diff: this has been open since July 31 with the AI-assisted review; the plugin and worker files were read on |
get_db_engine constructed the JobStore engine with no way to pass SQLAlchemy engine or pool options. Deployments behind managed Postgres could not set pool_pre_ping or pool_recycle, so the first async job submitted after an idle gap failed with "connection is closed". Forward **engine_kwargs to the engine factory, and read pool_pre_ping and pool_recycle from NAT_JOB_STORE_POOL_PRE_PING and NAT_JOB_STORE_POOL_RECYCLE when they are not passed explicitly. An engine is built in each process that reaches the job store and not every call site threads these settings through, so the environment covers the processes that inherit it. An unparseable value raises rather than silently falling back to the default, except when the caller supplies that setting explicitly, in which case the variable is left unread. Pooling defaults are unchanged when neither the keyword arguments nor the environment variables are set. Closes NVIDIA#2123 Signed-off-by: Jon Lambson <jonlambson@gmail.com>
f9d1fc0 to
32cb07a
Compare
|
@chuenchen309 You are right, and thank you for reading the actual code rather than the description. I have corrected the PR description, the docstring, the docs, and the commit message. Your point stands as written: Checking it turned up two more errors of mine that you did not claim, both worse than the one you did:
The second one exposes a real limitation I had not documented: with a separately managed I have left the implementation as is, since it is the smaller change and it resolves the reported failure, but the description now presents the choice as a preference for a maintainer to settle rather than as a constraint. If the YAML surface is wanted, I will add the config field, the CLI flag, and explicit threading through |
|
@willkill07 Sorry to ping directly. This has been open since July 31 with The CI pipeline has not run on this PR yet. It passes locally: the |
Description
Closes #2123
get_db_enginebuilt the JobStore engine ascreate_engine_fn(db_url, echo=echo), so SQLAlchemy pool options could not be set. Behind managed PostgreSQL, idle pooled connections are dropped server side without the client noticing, and the first async job submitted after an idle gap fails withconnection is closed. It self-heals on the next request, so the cost is one failed submission per idle gap.Changes
get_db_engineaccepts**engine_kwargsand forwards them to the engine factory.pool_pre_pingandpool_recyclefall back toNAT_JOB_STORE_POOL_PRE_PINGandNAT_JOB_STORE_POOL_RECYCLEwhen not passed explicitly. Explicit keyword arguments take precedence.ValueErrornaming the variable, instead of silently leaving the default in place. A typo in the setting that exists to prevent this failure should not reproduce the failure.Pooling defaults are unchanged when neither the keyword arguments nor the environment variables are set.
Environment variables now, config field is a maintainer's call
An earlier revision of this description claimed a
FastApiFrontEndConfigfield would reach only the parent process. That was wrong, and @chuenchen309 was right to push on it.db_urlis already such a field, and it reaches other processes because the parent resolves it and writes it intoos.environ. Pool settings could ride the same path.Checking that claim turned up two further errors of mine, both now fixed in the docstring, the docs, and the commit message:
os.environ.update()infastapi_front_end_plugin.pyruns at line 159, afterLocalClusteris created at line 122 and before uvicorn or gunicorn starts at line 179. It serves the API server workers, not the Dask workers. The Dask side receivesdb_urlas an explicitdask_client.submit()argument.nat serveand the workers inherit the environment at spawn.That last point exposes a real limitation, now documented: with a separately managed
scheduler_address, those workers inherit nothing from the API server host and need the variables set in their own environment. Threading the settings explicitly, the waydb_urlalready is, would close that gap.So the honest framing is that this PR is the smaller change and it resolves the reported failure, but the choice between it and a YAML surface is a preference about the config surface rather than a constraint. I am happy to add a
FastApiFrontEndConfigfield, a matching CLI flag, and explicit threading throughperiodic_cleanupandrun_generationif a maintainer wants the wider fix. The environment fallback stays useful either way for processes that receive no explicit arguments.On defaulting
pool_pre_pingto trueLeft out. It is a behavior change for existing deployments and is not needed to resolve the issue now that the setting is reachable. Happy to default it for non-SQLite URLs if you would rather have it on out of the box.
How to verify
Requires the
async_endpointsextra.Covers forwarding on the sync and async paths, both environment variables, explicit keyword arguments overriding the environment, invalid values raising, and defaults staying unchanged when nothing is configured.
By Submitting this PR I confirm: