Airflow integration
Airflow is an orchestration adapter around framework dispatch. Step code never imports Airflow.
Manifest-driven DAG generation
Section titled “Manifest-driven DAG generation”drtoller_step_runner.py scans configured roots, loads only step manifests, deduplicates by step_id, and creates one unscheduled DAG for each manifest with orchestrator.dag_id.
Each DAG contains one PythonOperator task (run_step), uses max_active_runs=1, and binds a fixed step id. dag_run.conf.step_id may be omitted; if present and different, execution fails.
orchestrator: dag_id: normalize_v1 step_id: normalize connections: [minio_s3, postgres_app] artifacts_root: env:DRTOLLER_ARTIFACTS_ROOT retries: 0 retry_delay_s: 60retries / retry_delay_s apply to the Airflow PythonOperator (defaults 0 / 60). Leave retries at 0 unless the task is safe to repeat — an OOM inflate must not run three times. Set retries: 3 when you want MinIO/DNS blips after a compose recreate to recover.
Step discovery
Section titled “Step discovery”Priority:
DRTOLLER_STEPS_ROOTS_FILE— newline-separated roots;DRTOLLER_STEPS_ROOTS— colon-separated roots;DRTOLLER_STEPS_ROOT— one root;- legacy development mounts/fallbacks.
A direct <root>/<step_id>/<step_id>.drtml lookup is attempted first, then recursive discovery validates manifest.step_id.
Triggering a run
Section titled “Triggering a run”build_trigger_conf() sends a minimal payload: step_id, normalized run_id, artifacts_root, and non-empty user fields. client.trigger_dag_run() unpauses the DAG (PATCH is_paused: false) then posts to Airflow REST /api/v1/dags/<dag_id>/dagRuns.
The same trigger is used by drtoller run --via airflow, POST /v1/runs with via: airflow, and Streamlit. Worker-side merge is prepare_run_from_conf (same hooks as local CLI).
Environment:
AIRFLOW_BASE_URLAIRFLOW_USERNAME(orAIRFLOW_USER)AIRFLOW_PASSWORD
Credentials should be provided by deployment secrets; defaults are development-only.
Worker-side parameter construction
Section titled “Worker-side parameter construction”run_task builds the worker RunContext through prepare_run_from_conf (same merge as local CLI / HTTP via=local):
- discovers and loads the manifest;
- removes reserved
step_id,run_id,artifacts_rootkeys; - merges user overlay with
params_defaults; - calls optional
orchestrator.params_hook; - applies
orchestrator.env_fallbacks/env_fallback_unless; - mirrors run id into
runtime.run_idand, for legacy mapping mode,mapping.run_idwhen absent; - applies declared connection hooks.
The resulting RunContext is passed to processing.dispatch.run_from_manifest(). If the manifest lists minio_s3, the task waits until MINIO_ENDPOINT hostname resolves (wait_endpoint_resolvable) before dispatch — Docker DNS after Airflow recreate.
Connections
Section titled “Connections”orchestrator.connections declares external connection ids. Current builtin MinIO handling reads Airflow connection minio_s3 and translates login/password/extras into the storage S3 environment.
PostgreSQL and Qdrant transports resolve their named DRTML connections through framework DB integration. New Airflow connection types should be generic adapters keyed by declared connection id, never branches on step id.
Params hooks
Section titled “Params hooks”orchestrator: params_hook: acme_pipeline.normalize.params:complete_paramsSignature:
def complete_params(manifest, params: dict, user_params: Mapping) -> dict: ...Use it only to complete integration/runtime configuration. Domain policy should stay in the processor and explicit domain.* defaults.
Framework always pushes <step_id>_outputs from result.outputs (or the result itself). Extra values use declarative dot paths:
orchestrator: xcom: - key: manifests from: outputs.storage_manifests - key: documents from: outputs.docs_totalMissing path segments resolve to null rather than executing code.
Failure behavior
Section titled “Failure behavior”Manifest discovery/validation, fixed-step mismatch, connection lookup, params hook, dispatch, or runtime exceptions fail the Airflow task. Framework logs a bounded result preview after success.
Extending Airflow
Section titled “Extending Airflow”Add external-system translation under integration/airflow; keep DAG objects and hooks out of storage/processing/domain layers. Test generated DAG identity, minimal conf, merge order, connection translation, and XCom resolution independently.