Skip to content

feat(core): make JobStore connection pooling configurable - #2150

Open
jonthedecepticon wants to merge 1 commit into
NVIDIA:developfrom
jonthedecepticon:feat/2123-get-db-engine-kwargs
Open

feat(core): make JobStore connection pooling configurable#2150
jonthedecepticon wants to merge 1 commit into
NVIDIA:developfrom
jonthedecepticon:feat/2123-get-db-engine-kwargs

Conversation

@jonthedecepticon

@jonthedecepticon jonthedecepticon commented Jul 31, 2026

Copy link
Copy Markdown

Description

Closes #2123

get_db_engine built the JobStore engine as create_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 with connection is closed. It self-heals on the next request, so the cost is one failed submission per idle gap.

Changes

  • get_db_engine accepts **engine_kwargs and forwards them to the engine factory.
  • pool_pre_ping and pool_recycle fall back to NAT_JOB_STORE_POOL_PRE_PING and NAT_JOB_STORE_POOL_RECYCLE when not passed explicitly. Explicit keyword arguments take precedence.
  • Unparseable values raise ValueError naming 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.
  • Both variables are documented under Asynchronous Generate in the REST API reference.

Pooling defaults are unchanged when neither the keyword arguments nor the environment variables are set.

Why environment variables rather than a config field

The JobStore engine is built in more than one process. fastapi_front_end_plugin.py writes NAT_JOB_STORE_DB_URL into the environment so the Dask worker subprocesses inherit it, fastapi_front_end_plugin_worker.py reads it back, and JobStore.__init__ builds its own engine from it. A FastApiFrontEndConfig field would configure the parent process only and leave the worker engines on the defaults, which is the wrong half of the problem. The environment is the existing transport for this subsystem, and get_db_engine already resolves db_url the same way.

I am happy to add a FastApiFrontEndConfig field and a matching CLI flag on top of this if you would prefer the YAML surface as well. It would be purely additive, and the environment fallback is still required for the workers either way.

On defaulting pool_pre_ping to true

Left 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_endpoints extra.

uv run pytest packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_job_store.py -k get_db_engine

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:

  • I am familiar with the Contributing Guidelines.
  • We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
    • Any contribution which contains commits that are not Signed-Off will not be accepted.
  • When the PR is ready for review, new or existing tests cover these changes.
  • When the PR is ready for review, the documentation is up to date with these changes.

Summary by CodeRabbit

  • New Features
    • Added configurable database connection pooling for asynchronous job history and metadata.
    • Supports connection health checks and connection recycling through environment settings.
    • Explicit engine settings take precedence over environment-based defaults.
  • Bug Fixes
    • Added validation and error handling for invalid pooling configuration values.
  • Documentation
    • Documented the new settings, defaults, behavior, and support for worker processes.

@jonthedecepticon
jonthedecepticon requested a review from a team as a code owner July 31, 2026 16:57
@copy-pr-bot

copy-pr-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6f712477-c789-4a9c-94c8-d65d294c6ad3

📥 Commits

Reviewing files that changed from the base of the PR and between 30b514d and f9d1fc0.

📒 Files selected for processing (3)
  • docs/source/reference/rest-api/api-server-endpoints.md
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/async_jobs/job_store.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_job_store.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/async_jobs/job_store.py
  • docs/source/reference/rest-api/api-server-endpoints.md
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_job_store.py

Walkthrough

The 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.

Changes

Job store pool configuration

Layer / File(s) Summary
Engine pool configuration and validation
packages/nvidia_nat_core/src/nat/front_ends/fastapi/async_jobs/job_store.py, packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_job_store.py, docs/source/reference/rest-api/api-server-endpoints.md
get_db_engine accepts engine keyword arguments and merges them with validated NAT_JOB_STORE_POOL_PRE_PING and NAT_JOB_STORE_POOL_RECYCLE values. Explicit arguments take precedence. Tests cover sync and async engines, defaults, parsing, precedence, and invalid values. Documentation describes the settings and affected processes.

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
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise, descriptive, within 72 characters, and uses imperative mood.
Linked Issues check ✅ Passed The changes satisfy issue #2123 by forwarding engine and pool options and supporting validated environment configuration.
Out of Scope Changes check ✅ Passed The code, documentation, and tests remain within the linked issue's scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

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

📥 Commits

Reviewing files that changed from the base of the PR and between c10dc4d and 30b514d.

📒 Files selected for processing (3)
  • docs/source/reference/rest-api/api-server-endpoints.md
  • packages/nvidia_nat_core/src/nat/front_ends/fastapi/async_jobs/job_store.py
  • packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_job_store.py

Comment thread packages/nvidia_nat_core/src/nat/front_ends/fastapi/async_jobs/job_store.py Outdated
Comment thread packages/nvidia_nat_core/tests/nat/front_ends/fastapi/test_job_store.py Outdated
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. The
environment is the only configuration that reaches the engines built in
the Dask worker subprocesses. 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>
@jonthedecepticon
jonthedecepticon force-pushed the feat/2123-get-db-engine-kwargs branch from 30b514d to f9d1fc0 Compare July 31, 2026 17:06
@jonthedecepticon

Copy link
Copy Markdown
Author

Thanks, addressed two of the three.

  • Environment validation on an overridden setting: fixed. _apply_pool_env_defaults now reads a variable only when the matching key is absent from engine_kwargs, so an explicit argument leaves the variable unread rather than validated. Added a regression test covering malformed values for both variables alongside explicit overrides.
  • no value: added to the parameter table, along with a surrounding-whitespace case.

Skipping the Google-style docstring change. job_store.py is entirely NumPy-style (nine Parameters sections, no Args: blocks), and this change extends the existing get_db_engine docstring rather than introducing a new one. Converting only this function would leave the file inconsistent. Happy to convert the whole module in a separate PR if that is the direction you want.

@jonthedecepticon

Copy link
Copy Markdown
Author

Maintainers: this PR has no labels, so the Label Checker is failing with Missing category & breaking labels. I cannot set them as an external contributor. Could someone add feature request and non-breaking?

A vet for copy-pr-bot would also be appreciated, since the CI pipeline has not run on this PR yet. In the meantime it passes locally: the get_db_engine tests, copyright.py --verify-apache-v2, path_checks.py, pre-commit on the changed files, Vale, and the docs HTML build. The branch is current with develop.

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

Labels

None yet

Projects

None yet

1 participant