deployments
Deployment identity and readiness for the background metadata runtimes.
Both metadata flows register under the same Prefect flow name (background)
with distinct deployment names, and are addressed by the
"<flow-name>/<deployment-name>" strings run_deployment accepts. Those
strings are load-bearing in four places — the flows' own serve() calls, the
orchestrator's triggers and chain automation, run_pod's triggers, and the
refresh flow — so they live here rather than being retyped at each site: a
mismatched literal does not fail loudly, it silently produces a deployment
nothing ever triggers.
wait_for_deployment lives here for the same reason. serve() registers a
deployment asynchronously from a daemon thread, so any code that triggers a run
may get there first; every serving process therefore needs the same
poll-until-registered probe.
Also home to the run_type values every flow run this system creates is tagged
with, and the map from those to the deployment each is submitted against. They
sit beside the handles because they are the same kind of thing — identity every
submitter, every dedup check and both recovery sweeps must agree on — and
because what has to hold of them is mutual: they must all be distinct, and in
particular none may collide with BACKGROUND_DAG_RUN_TYPE, since
flows.dag.recovery finds its work by matching that tag and would otherwise
start replaying metadata runs it has no spec for. That invariant is checkable at
a glance in one list and unverifiable spread across the runtime packages, which
is also why BACKGROUND_DAG_RUN_TYPE lives here despite having no deployment:
it is a run_type, and this is where run types are.
Also home to ConfigError, the misconfiguration signal both flows raise (see
the class docstring for why the type matters).
Module
Functions
wait_for_deployment
async def wait_for_deployment( deployment_name: str, timeout: float = 30.0, poll_interval: float = 0.2,) ‑> bool:Poll the Prefect API until deployment_name is registered.
Intended to be awaited by a process that has just started serve() in a
background thread, before it submits any run. serve() registers the
deployment asynchronously, so a triggerer that does not wait can call
run_deployment against a deployment that does not exist yet.
Coroutine rather than a blocking function so the caller owns the event loop:
the orchestrator drives it through its _run_async bridge (Flask-SocketIO
runs handlers on plain threads) and run_pod through asyncio.run. Probing
inside one loop also avoids standing up and tearing down an event loop on
every poll for the whole timeout.
Arguments
deployment_name: The full"<flow-name>/<deployment-name>"string, e.g.FILE_METADATA_DEPLOYMENT.timeout: Maximum seconds to wait before giving up.poll_interval: Seconds between consecutive API probes.
Returns
True when the deployment was found within timeout seconds, False
if the timeout was reached first. Never raises: a caller that cannot
confirm readiness should degrade (skip indexing) rather than abort
startup, so the failure is reported by return value.
Global variables
BACKGROUND_DAG_RUN_TYPE-run_typevalue marking an in-process background DAG run. Distinct from the metadata runtimes' values so the two never dedup against each other, and so neither recovery sweep ever matches the other's work.
DEPLOYMENT_BY_RUN_TYPE : dict[str, str]- The deployment handle each metadatarun_typeis served and resubmitted against. Pure identity, so it lives with the handles rather than with the recovery sweep that reads it.
DEPLOYMENT_POLL_INTERVAL_SECONDS- Gap between consecutive registration probes.
DEPLOYMENT_READY_TIMEOUT_SECONDS- How long a triggerer waits for a deployment to appear before giving up.
FILE_METADATA_DEPLOYMENT- Fully-qualified"<flow-name>/<deployment-name>"handles accepted byrun_deploymentandread_deployment_by_name. The orchestrator andrun_podmust agree on these: a live run tagged by either triggerer is only visible to the other's dedup check if both scope it to the same deployment.
FILE_METADATA_DEPLOYMENT_NAME- Deployment names as passed toflow.serve(name=...).
FILE_METADATA_REFRESH_RUN_TYPE-run_typevalues for the remaining flow runs a pod produces. None of them are dedup keys — they exist so that no row in the Prefect UI is unlabelled, which is what makes the UI usable for support. Each is distinct fromBACKGROUND_DAG_RUN_TYPEso thatflows.dag.recoverynever matches them.
FILE_METADATA_RUN_TYPE- The metadata runtimes' ownrun_typevalues. Named here rather than spelled as literals at each submission site, becausebitfount.runtimes.recoverydiscovers lost runs by these values and a typo at one submitter would make those runs silently unrecoverable.
FLOW_NAME- Prefect flow name shared byfile_metadata_runtimeandscan_metadata_runtime. They coexist under it because deployment names, not flow names, disambiguate them.
Classes
ConfigError
class ConfigError(*args, **kwargs):Raised when a metadata runtime's datasource configuration is invalid.
A dedicated type (rather than a bare ValueError) is what lets each flow's
except Exception handler call mark_run_failed, store the message, and
re-raise unconditionally — so Prefect records the run as failed rather
than successful. Operators watching Prefect flow state then get an accurate
signal without inspecting the cache DB or a callback payload.
Subclasses ValueError rather than BitfountError: the misconfiguration is
always a bad argument to the flow (an unsupported datasource type, a missing
path or connection string), and callers that already catch ValueError
around flow invocation should keep catching it.