fix(compliance-checks): make serverless compliance job runnable (deploy backend source + __file__-free bootstrap) - #795
Conversation
…erless
The compliance-checks workflow is submitted as a spark_python_task that runs
on Databricks serverless, where the entry script is executed via
exec(compile(...)) in a namespace with no __file__ bound. Evaluating
Path(__file__) at module import time raised NameError before main() ever ran,
so the scheduled compliance job died on startup every time on serverless.
Guard the sys.path bootstrap with globals().get("__file__"): use the
__file__-derived source root when present (unchanged local behaviour), and fall
back to the working directory (the deployed workflow folder on serverless) when
absent. The whole bootstrap is wrapped in try/except so it can never abort
module load.
Adds a smoke test that execs the module source with no __file__ in globals
(faithfully simulating serverless) and asserts no NameError, plus a case
proving normal import with __file__ present still works.
Fixes #685
Co-authored-by: Isaac
…erless Address cross-review of #685: - Serverless (no __file__): do NOT fabricate a sys.path entry. There is no reliable signal to derive the real source root -- the deployer uploads only the workflow folder (not the src tree) and serverless job environments cannot carry env vars ("compute.Environment doesn't support env_vars directly"). A cwd-based guess could prepend an unrelated dir and mask similarly named packages. The module's app imports are lazy (inside functions), so module import needs no sys.path entry; runtime from-src.* resolution relies on the environment/PYTHONPATH/installed package. If insufficient it fails later with a clear ImportError, not a cryptic NameError at load. - __file__ present (local/normal cluster): behaviour unchanged -- source root is Path(__file__).parent.parent.parent, prepended to sys.path. - Narrowed the exception handling: only the __file__-branch insert is guarded, and it warns to stderr instead of silently swallowing, so a real bootstrap failure is diagnosable while module import can never crash. Strengthen the smoke test to close the false-PASS gap: the serverless simulation now chdirs into a deployed-workflow-shaped temp dir and asserts sys.path is unchanged (no fabricated/cwd-derived entry), and the __file__ case asserts the correct source root is prepended. sys.path is snapshotted/restored per test; dependency stubs cannot mask a wrong entry because assertions inspect sys.path directly. Fixes #685 Co-authored-by: Isaac
Co-authored-by: Isaac
mvkonchits-db
left a comment
There was a problem hiding this comment.
Reviewed with the code-review skill. The fix correctly removes the import-time NameError from referencing __file__ at module load, but I don't think it makes the workflow actually runnable on serverless — leaving as a comment rather than approving so it can be verified.
-
The crash may just move later. On serverless the bootstrap now inserts nothing on
sys.path. Module load then succeeds, butmain()later hits lazy imports likefrom src.controller.compliance_manager import ComplianceManagerandfrom src.db_models.compliance import CompliancePolicyDb. The serverless env spec installs onlydatabricks-sdk/sqlalchemy/psycopg2-binary(not the ontos backend), so unless the runtime already has the backendsrcparent onPYTHONPATH, those raiseModuleNotFoundError— the same job failure, just later. -
Possible off-by-one in the non-serverless path. The insert uses
Path(__file__).parent.parent.parent=src/backend/src(thesrcpackage dir itself). Butfrom src.*resolves only whensrc/backend(the package's parent) is onsys.path. Inserting the package dir makesimport srcunresolvable in any env that relies solely on this insert. -
Tests don't cover the failure point. Both new tests set
__name__ != '__main__', somain()never runs and the lazyfrom src.*imports are never exercised — the suite passes without touching the thing that actually fails on serverless. Alsoassert sys.path == sys_path_beforeis order-dependent and can flake if a real dep import mutatessys.pathfirst.
Suggestion: validate against a real serverless run (or a test that invokes main()/the lazy imports under a simulated serverless sys.path) before merging, and double-check the insert targets src/backend, not src/backend/src.
Co-authored-by: omnigent <noreply@omnigent.ai>
Co-authored-by: omnigent <noreply@omnigent.ai>
Co-authored-by: omnigent <noreply@omnigent.ai>
Co-authored-by: omnigent <noreply@omnigent.ai>
|
Thanks for the careful review, @mvkonchits-db — all three points are addressed in the reworked branch, and I validated it with a real end-to-end serverless run. 1. "Crash just moves later" / backend not on serverless — fixed by actually deploying the backend. The deployer now builds a Verified on a real serverless run against a live Ontos Lakebase (9 policies, 13 data products): the job connects, 2. Off-by-one — fixed. The bootstrap now targets 3. Test coverage — the failure point is now exercised. A new hermetic test builds the real archive, strips the backend roots from Scope note: this PR is intentionally scope-limited to #685 (serverless import / |
Co-authored-by: omnigent <noreply@omnigent.ai>
Co-authored-by: omnigent <noreply@omnigent.ai>
…tings-807 fix(compliance-checks): initialize application settings in serverless job (evaluate 0 -> entities)
Fixes #685
Summary (plain language)
Ontos runs its compliance checks as a scheduled Databricks job on serverless compute. That job could not run on serverless at all, for two compounding reasons:
NameErrorat module load — the entry script's first executable line derived its own folder from Python's__file__. On serverless the script is executed viaexec(compile(...))in a namespace where__file__is not bound, soPath(__file__)raisedNameErrorbeforemain()ran.ModuleNotFoundError: No module named 'src'— even past that, the job doesfrom src.controller.compliance_manager import ComplianceManagerat runtime, but the backendsrcpackage was never deployed to serverless (the deployer only uploaded the workflow folder). So the run connected to the database, loaded policies, then crashed on the import.This PR makes the job genuinely runnable on serverless: the backend
srcpackage is packaged and shipped alongside the workflow, extracted locally at runtime, and put onsys.path; and the module-load bootstrap no longer depends on__file__.Root cause confirmed on the real serverless job
The production Compliance Checks job on serverless fails today at exactly this point (real run, current code):
Change (5 files)
utils/workspace_deployer.py— when a workflow setsdeploy_backend_source, build abackend_src.zipof the backendsrcpackage and upload it beside the deployed workflow script.controller/jobs_manager.py— whendeploy_backend_sourceis set, pass the uploaded archive's/Workspacepath to the job as--backend_source_path(with a directory fallback when no archive is deployed).workflows/compliance_checks/compliance_checks.py__file__-free module bootstrap: with__file__present, behaviour is unchanged; without it, the module-level insert is guarded so import never aborts.src/backend(notsrc/backend/src), sofrom src.*resolves._add_backend_source_path(): if--backend_source_pathis a.zip, extract it to a local temp directory (validated to contain thesrcpackage, with a zip-slip / path-traversal guard on every member) and prepend that local directory tosys.path; if it is a directory, insert it directly. This is required because CPython cannotzipimportfrom the/WorkspaceFUSE mount — a naive "put the zip onsys.path" approach raisesNotADirectoryErroron serverless.workflows/compliance_checks/compliance_checks.yaml— enabledeploy_backend_source: true, add the--backend_source_pathjob parameter, and expand the serverless environment dependencies to cover the import closure (gitpython,pydantic[email],pydantic-settings, …).tests/test_compliance_checks_workflow.py— hermetic coverage that builds the real archive, strips the backend root fromsys.path,execs the module without__file__, and asserts both lazy imports (src.controller.compliance_manager,src.db_models.compliance) resolve from the extracted local directory — not the zip or the repo. Plus both-branch fallback and normal-__file__cases.Serverless evidence — the fix works on real compute
Deploying the fixed script +
backend_src.zipand running on serverless, the exact import thatModuleNotFoundErrors in production now succeeds:Gate output
Nothing under
.github/workflows/is touched.Full end-to-end serverless validation
The fix was validated with a real serverless run of the deployed Compliance Checks job against a live Ontos Lakebase (
ontos-db, schemaapp_ontos, 9 active policies, 13 data products):The job runs to completion — the
from src.*imports that previously raisedModuleNotFoundErrornow resolve on serverless. This confirms the #685 fix end-to-end.Scope & follow-up (#807)
This PR is scope-limited to the original issue #685 (the serverless import /
__file__startup failure). The end-to-end run surfaced a separate, deeper bug in the compliance workflow — filed as #807 — which is out of scope for this PR and will be fixed there: