feat: add prefect_enabled config option to run ingestions without Prefect - #336
Open
minhajuddin2510 wants to merge 1 commit into
Open
feat: add prefect_enabled config option to run ingestions without Prefect#336minhajuddin2510 wants to merge 1 commit into
prefect_enabled config option to run ingestions without Prefect#336minhajuddin2510 wants to merge 1 commit into
Conversation
… Prefect Submitting a resource fails outright on deployments where CKAN cannot write $PREFECT_HOME: ERROR [ckanext.datapusher_plus.logic.action] Error submitting job to DataPusher: [Errno 13] Permission denied: '/root/.prefect/profiles.toml' That is not a Prefect outage — `submit_flow_run`'s `from prefect.deployments import run_deployment` runs Prefect's settings bootstrap, which creates `$PREFECT_HOME/profiles.toml` (default `$HOME/.prefect`). A CKAN process running with HOME=/root but no write access there cannot even import the library, so no amount of server configuration helps. Add `ckanext.datapusher_plus.prefect_enabled` (default true). Setting it to false turns Prefect off entirely: `datapusher_submit` enqueues the job on CKAN's own background queue and the new `jobs/local_runner.py` runs the same nine ingestion stages in-process, with nothing on the path importing `prefect`. Operators run `ckan jobs worker` instead of a Prefect server, worker, and work pool. The local runner keeps the Jobs/Logs tables, the datapusher_hook callbacks, the complete-with-skip contract, the flow_timeout deadline, and the post-database-failure datastore cleanup. It does not provide per-stage retries, result caching, the run graph/artifacts/events, or human-in-the-loop PII review — with Prefect off, a job crossing pii_review_threshold aborts before any datastore write rather than suspending for an approval that can never arrive. A database-stage failure deliberately leaves the datastore alone (that stage can fail before touching anything, and dropping there would destroy data the run never wrote). The task_status row records the RQ job id as `rq_job_id` rather than `flow_run_id`, so nothing builds a Prefect-UI deep link out of it. The Prefect-free half of the pipeline moves out of prefect_flow.py into the new jobs/pipeline_core.py — the CKAN status callback, input validation, RuntimeContext construction, the stage invoker and its StageAbort signal, and the datastore rollback body — shared verbatim by both runners. prefect_flow keeps its historical private names as aliases, so custom flows composed from its @task primitives are unaffected; tests that patched prefect_flow.dsu / .QSVCommand / .Path now patch pipeline_core. Unit suite: 307 passed, 1 failed (test_quoted_csv_inference_matrix, a pre-existing qsv-binary-dependent failure present on the base commit too). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Submitting a resource fails outright on deployments where CKAN cannot write
$PREFECT_HOME:This is not a Prefect outage.
prefect_client.submit_flow_run()doesfrom prefect.deployments import run_deployment, and that import runs Prefect's settings bootstrap, which creates$PREFECT_HOME/profiles.toml(default$HOME/.prefect). A CKAN process running withHOME=/rootbut no write access there cannot even import the library, so no server configuration fixes it.What changed
New setting, default
true:ckanext.datapusher_plus.prefect_enabled = falseWith it off,
datapusher_submitenqueues the job on CKAN's own background queue and the newjobs/local_runner.pyexecutes the same nine ingestion stages in-process — no Prefect server, worker, work pool, orimport prefectanywhere on the path. Operators runckan jobs workerinstead.enqueue_job(RQ submit),run_job(the nine stages),get_running_resource_ids(RQ-queue scan for the duplicate-submission check)jobs/local_runner.py(new)RuntimeContextconstruction, stage invoker +StageAbort, datastore rollback,resolve_intjobs/pipeline_core.py(new)_orchestrator()/_submit_job()routinglogic/action.pyprefect-deployrefuses to run in this mode;migrate-from-rqskips the reachability check; startup log linejobs/events.py,cli.py,plugin.pyUnchanged in local mode:
Jobs/Logstables, the job-status page,datapusher_hookcallbacks (running → complete/error), CLI submit/resubmit, DRUF, the complete-with-skip contract, and theflow_timeoutdeadline (also passed to RQ as the job timeout — RQ's own default is 180s, which would kill any real ingestion mid-COPY).Reviewer notes — three deliberate behavior decisions
pii_review_threshold > 0asks a human to approve a PII-flagged run. Nothing can hold a job open without Prefect, so the only safe reading of that intent is "do not load it" — the job errors before any datastore write. Documented in the README table and in the error message itself.database_task.on_rollback. But the database stage can raise before touching anything ("Could not connect to the Datastore"), and dropping there would destroy intact data the run never wrote. Both paths are tested.rq_job_id, notflow_run_id. Otherwise a deployment with a staleprefect_ui_basewould render a Prefect UI deep-link pointing at an RQ id.datapusher_statusalready returnsjob_url: Nonewhenflow_run_idis absent, so its response shape is unchanged.Refactor note
prefect_flow.pyshed the Prefect-free half intopipeline_core.py(~200 lines moved, not rewritten) so there is one implementation per behavior.prefect_flowbinds the moved names to its historical private spellings (_StageAbort,_build_runtime_context,_stage_run, …), so custom flows composed from its@taskprimitives are unaffected. Tests that patchedprefect_flow.dsu/.QSVCommand/.Pathnow patchpipeline_core— same module objects, owner-correct target.Testing
Unit suite (
pytest tests/ --ignore=tests/integration): 307 passed, 1 failed vs 279 passed, 1 failed on the base commit. The single failure istest_quoted_csv_inference_matrix, pre-existing and unrelated (needs a real qsv 20.x binary locally).28 new tests in
tests/test_local_runner.py: the config switch, stage order, complete-with-skip, datastore-dump short-circuit, both rollback paths, both PII-gate paths, the RQ helpers, anddatapusher_submitrouting (including which key the task_status row gets). One of them shells out to a subprocess to assert that importing the disabled path pulls in zeroprefectmodules — the invariant this whole PR rests on.Integration tests were not run (no docker-compose stack in the dev environment); a reviewer with the stack up should sanity-check that the default Prefect path is untouched end-to-end.
Alternative for operators who want to keep Prefect
Point
PREFECT_HOMEat a directory the CKAN user owns (e.g./var/lib/ckan/prefect) in both the CKAN and worker environments. Documented alongside the new mode in the README troubleshooting table.🤖 Generated with Claude Code