flow
Prefect flow for the file metadata runtime.
Entrypoint
file_metadata_runtime
Top-level flow — call this to collect and persist metadata for a
single datasource. The orchestrator triggers it via a Prefect deployment
(run_deployment("background/file_metadata_runtime", ...)) immediately
after a pod is successfully started.
Datasource routing
The flow receives a datasource_type string (e.g. "bitfount.CSVSource")
and resolves it to the actual class using the same lookup path that
setup_datasource uses in bitfount.runners.config_utils:
DataSourceType(datasource_type).name— resolves the enum value (e.g."bitfount.CSVSource") to its enum member name (e.g."CSVSource"), falling back to the raw string for plugin datasources not in the enum.getattr(importlib.import_module("bitfount.data"), cls_name)— imports the class from thebitfount.datapublic surface.issubclass(cls, FileSystemIterableSource)— determines whether the datasource walks a directory of files, without maintaining a hardcoded allowlist of type names.issubclass(cls, _SQLSource)— identifies DB-backed datasources whose only input is a connection string.- Everything else with a
patharg falls through to single-file metadata (e.g.CSVSource).
Run-state tracking
Run is written to the cache DB at flow start (status
"running") and updated on completion ("complete") or failure
("failed"). The refresh flow reads this table before re-triggering
to avoid running two indexing passes for the same datasource concurrently.
Completion signalling
When orchestrator_callback_url is provided, the flow POSTs a
completion payload to that URL via the notify_orchestrator task
(retries=3, retry_delay_seconds=5) so the orchestrator can forward a
file_metadata_complete Socket.IO event to the desktop app. The
notification is sent regardless of whether the flow succeeded or failed,
before any exception is re-raised.
Flow timeout
timeout_seconds is read from settings.metadata_flow_timeout_seconds,
which defaults to None (no timeout) — the same as Prefect's own default.
A walk over a very large tree is legitimately long-running and cannot be
told apart from a wedged run by duration alone, so no cap is baked in;
liveness is detected via flow-run heartbeats and the zombie-reaper
automation instead. Operators who know their expected upper bound may set
one via BITFOUNT_METADATA_FLOW_TIMEOUT_SECONDS. Note this is read at
import time, so the environment must be set before the flow module loads.
Config-error handling
Misconfigured datasources (unsupported type, missing path, missing
connection string) raise ConfigError (a ValueError subclass shared with
scan_metadata_runtime; see bitfount.runtimes.deployments). This propagates
through the except Exception handler which calls mark_run_failed and stores
the error message, then is re-raised so that Prefect records the flow run as
failed rather than successful. Operators monitoring Prefect flow state
therefore see an accurate signal without needing to inspect the callback payload
or the cache DB.
Module
Functions
file_metadata_runtime
def file_metadata_runtime( pod_name: str, datasource_name: str, datasource_type: str, cache_db_path: str, orchestrator_callback_url: str | None = None, path: str | None = None, connection_string: str | None = None, only_paths: list[str] | None = None,) ‑> int:Collect and persist file metadata for a single datasource.
This flow is triggered as a fire-and-forget background task immediately
after a pod is successfully started (i.e. the dataset has been created).
The orchestrator submits it via
run_deployment("background/file_metadata_runtime", timeout=0) so it
never blocks the HTTP response.
A Run is written at the start (status "running")
and updated on completion or failure. The refresh flow checks this
record before re-triggering to avoid concurrent indexing passes for the
same datasource.
On completion the flow POSTs a file_metadata_complete payload to
orchestrator_callback_url (when provided) so the orchestrator can
forward the event to the desktop app via Socket.IO. The notification is
sent whether the flow succeeds or fails.
Datasource routing uses issubclass checks against the resolved class
so that newly added subclasses are handled automatically without any
changes to this module:
FileSystemIterableSourcesubclasses → directory walk._SQLSourcesubclasses → DB connection string row.- Everything else with a
path→ single-file metadata (e.g. CSV). - Unresolvable or unsupported types → logged and skipped.
Arguments
pod_name: Name of the pod (used to derivetask_hash).datasource_name: Name of the datasource within the pod.datasource_type: Datasource type string from the pod config, e.g."bitfount.CSVSource"or"bitfount.DICOMSource".cache_db_path: Filesystem path to the pod'sbackground_cache.dbSQLite file. The flow opens its own cache connection for the duration of the run and closes it on exit.orchestrator_callback_url: Optional URL of the orchestrator'sPOST /pod/file-metadata-completeendpoint. When set, the flow POSTs a completion payload so the orchestrator can emit afile_metadata_completeSocket.IO event to the desktop app.path: File path (single-file sources) or directory path (FileSystemIterableSourcesubclasses).connection_string: DB connection string (_SQLSourcesubclasses).only_paths: When set, index exactly these paths (files or directories) instead of walking path, and skip the deletion prune. Used by the file watcher, which has already identified what is new. Ignored for non-FileSystemIterableSourcedatasources, which have no walk to scope. Any spelling is accepted — these and path are both normalized before being compared — and a path that lands outside path is refused with a warning. Seebitfount.runtimes.file_metadata.tasks._iter_stat_targets.
Returns
The number of FileMetadata records written to the cache.