file_metadata
file_metadata runtime package.
Re-exports the public API so callers can import directly from
bitfount.runtimes.file_metadata without knowing the internal
module layout:
from bitfount.runtimes.file_metadata import (
file_metadata_runtime,
file_metadata_refresh,
generate_prefect_task_hash,
)
Module
Submodules
- bitfount.runtimes.file_metadata.flow - Prefect flow for the file metadata runtime.
- bitfount.runtimes.file_metadata.functions - Shared helper functions for the file metadata runtime.
- bitfount.runtimes.file_metadata.refresh - Prefect flow for periodic re-indexing of stale file metadata.
- bitfount.runtimes.file_metadata.selection - Read-time selection of a datasource's files from the pod-wide inventory.
- bitfount.runtimes.file_metadata.tasks - Prefect tasks for the file metadata runtime.
Functions
file_metadata_refresh
async def file_metadata_refresh(staleness_days: int = 1) ‑> int:Re-index stale file metadata across all pods.
Scans every pod's background_cache.db under
~/.bitfount/cache/pods/, identifies datasources with rows older than
staleness_days, and submits a background/file_metadata_runtime
deployment run for each one — unless a non-stale indexing run for that
datasource is already active.
This flow is intended to be registered as a single long-lived Prefect
deployment via file_metadata_refresh.serve(cron=...) on orchestrator
startup. It uses global_limit=1 so only one refresh pass runs at a
time even if a scheduled tick fires while the previous pass is still
running.
Runs are submitted as fire-and-forget (timeout=0) so the refresh flow
returns as soon as all runs are scheduled, not when they complete.
is_flow_run_active (a Prefect flow-run tag query) prevents duplicate
runs from being scheduled for the same datasource; _is_run_active is
still called per datasource but only reaps orphaned bookkeeping rows.
Arguments
staleness_days: Number of days after which aFileMetadatais considered stale and eligible for re-indexing. Defaults to 1. Because a re-index rewritesindexed_aton every row of the datasource, no row is stale again until this window elapses — so this value, not the deployment's cron, is what sets the re-walk cadence. Ticking more often than the window does nothing.
Returns
The total number of file_metadata_runtime runs triggered.
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.
generate_prefect_task_hash
def generate_prefect_task_hash(pod_name: str, datasource_name: str) ‑> str:Return a stable, fixed-length task hash for a (pod, datasource) pair.
The hash is derived from "{pod_name}/{datasource_name}" so that it
is deterministic across restarts and serves as the composite primary-key
prefix in FileMetadata and Run.
This is the datasource leaf hash, and it plays two roles:
- It keys the datasource/run-level tables directly —
file_metadata,scan_metadata,runs,schema_versions— none of which a DAG step writes. - It is the leaf mixed into every per-step Merkle
task_hash(bitfount.flows.dag.hashing), which is what keeps two datasources on the same pod in separate partitions of a step's table.
Arguments
pod_name: The name of the pod.datasource_name: The name of the datasource within the pod.
Returns A 32-character hex string (the first 128 bits of the SHA-256 digest).