-
Notifications
You must be signed in to change notification settings - Fork 321
[Bug] dbt INVOCATION_COMMAND reports the Airflow worker's argv instead of the dbt command when using InvocationMode.DBT_RUNNER #2969
Copy link
Copy link
Labels
area:executionRelated to the execution environment/mode, like Docker, Kubernetes, Local, VirtualEnv, etcRelated to the execution environment/mode, like Docker, Kubernetes, Local, VirtualEnv, etcarea:loggingRelated to logging, like log levels, log formats, error logging, etcRelated to logging, like log levels, log formats, error logging, etcbugSomething isn't workingSomething isn't workingcustomer requestAn Astronomer customer made requested thisAn Astronomer customer made requested thisexecution:localRelated to Local execution environmentRelated to Local execution environmentgood first issueGood for newcomersGood for newcomerspriority:mediumMedium priority issues are important issues that may have a workaround and medium impactMedium priority issues are important issues that may have a workaround and medium impact
Description
Activity
Metadata
Metadata
Assignees
Labels
area:executionRelated to the execution environment/mode, like Docker, Kubernetes, Local, VirtualEnv, etcRelated to the execution environment/mode, like Docker, Kubernetes, Local, VirtualEnv, etcarea:loggingRelated to logging, like log levels, log formats, error logging, etcRelated to logging, like log levels, log formats, error logging, etcbugSomething isn't workingSomething isn't workingcustomer requestAn Astronomer customer made requested thisAn Astronomer customer made requested thisexecution:localRelated to Local execution environmentRelated to Local execution environmentgood first issueGood for newcomersGood for newcomerspriority:mediumMedium priority issues are important issues that may have a workaround and medium impactMedium priority issues are important issues that may have a workaround and medium impact
Bug description
When Cosmos invokes dbt in-process via
InvocationMode.DBT_RUNNER, dbt'sflags.INVOCATION_COMMANDresolves to the host process's command line — e.g. the Celery worker startup command — rather than the dbt command Cosmos actually ran.Users who log
{{ flags.INVOCATION_COMMAND }}from anon-run-endhook (or via packages such as dbt_artifacts / Elementary that persist invocation metadata) get rows like:instead of the expected:
This makes the invocation-command column useless for auditing which dbt selector / target / vars produced a given run.
Root cause
dbt-core builds the value from
sys.argv, unconditionally, with no dbtRunner-aware path (dbt/cli/flags.py, dbt-core 1.11.x — same in earlier 1.x):Cosmos calls
dbtRunner.invoke(cli_args)in the Airflow task process and never adjustssys.argv, so dbt sees the worker's argv (cosmos/dbt/runner.py::run_command).This is not specific to
ExecutionMode.WATCHER. Any code path that lands onInvocationMode.DBT_RUNNERis affected. It is easy to hit unknowingly becauseDbtLocalBaseOperator._discover_invocation_mode()(cosmos/operators/local.py) auto-selectsDBT_RUNNERwheneverdbt-coreis importable in the Airflow environment, andDbtProducerWatcherOperatorintentionally leaves that discovery in place. Reported by a user on Cosmos 1.14.2 who noticed it after adopting WATCHER, but it reproduces onmainand predates WATCHER.How to reproduce
dbt-coreimportable (soInvocationMode.DBT_RUNNERis auto-selected), Celery executor.on-run-endhook that inserts{{ flags.INVOCATION_COMMAND }}into an audit table.DbtDag/DbtTaskGroupwithout settinginvocation_modeexplicitly.Confirm the mode from the task log — it prints either
dbtRunner is available. Using dbtRunner for invoking dbt.orCould not import dbtRunner. Falling back to subprocess for invoking dbt.Expected behaviour
INVOCATION_COMMANDshould match the dbt command Cosmos ran, so thatDBT_RUNNERandSUBPROCESSproduce equivalent invocation metadata.Proposed fix
In
cosmos/dbt/runner.py::run_command, temporarily setsys.argvto the dbt command for the duration ofrunner.invoke()and restore it afterwards. The command list is already available there (command[0]is the dbt executable,command[1:]are the CLI args passed toinvoke), so the string dbt derives will match whatSUBPROCESSmode would have produced.This fits the existing structure:
run_commandalready composesexclude_dags_folder_from_sys_path(),change_working_directory(cwd)andenviron(env)around the invocation, so this would be one more restore-on-exit contextmanager next to them incosmos/dbt/project.py.Points to settle during implementation:
sys.argvis process-global. Restore must happen on every exit path (try/finally, as done today for_cleanup_dbt_adapters), and we should confirm behaviour for any in-process concurrent dbt invocations (e.g.dbt lsgraph parsing in the DAG processor) rather than assume one-invocation-per-process.run_commandcallers (including parsing-timedbt ls) or only operator execution.Workaround
Set the invocation mode explicitly, which sends dbt through a real subprocess whose argv is the dbt command:
Trade-off:
SUBPROCESSis measurably slower thanDBT_RUNNER— the benchmark in #850, which introduced dbtRunner, showed ~8.4s vs ~23.8s for 10 models (roughly 1-2s of extra overhead per task). Fixing this in Cosmos would let users keep dbtRunner's speed and get the correct logged command.Versions
main