Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ def date_param():
'tasks failed-deps example_bash_operator runme_0 --logical-date "{date_param}"',
'tasks states-for-dag-run example_bash_operator "manual__{date_param}"',
'tasks states-for-dag-run example_bash_operator --logical-date "{date_param}"',
'tasks state example_bash_operator runme_0 "manual__{date_param}"',
'tasks state example_bash_operator runme_0 --logical-date "{date_param}"',
'tasks clear example_bash_operator --dag-run-id "manual__{date_param}" --task-ids runme_0 -o json',
# Task Instances commands
'taskinstances get example_bash_operator "manual__{date_param}" runme_0',
Expand Down
2 changes: 1 addition & 1 deletion airflow-ctl/docs/images/command_hashes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:a5b644c5da8889443bb40ee10b599270
pools:19efe105b9515ab1926ebcaf0e028d71
providers:34502fe09dc0b8b0a13e7e46efdffda6
taskinstances:bea84117114c2438eb7e7026f6bb7042
tasks:ea587dc805cadbce81cd640d357f2661
tasks:eb70701dfe1b9baeda39d5eea07fde5f
variables:f8fc76d3d398b2780f4e97f7cd816646
version:31f4efdf8de0dbaaa4fac71ff7efecc3
plugins:4864fd8f356704bd2b3cd1aec3567e35
Expand Down
78 changes: 41 additions & 37 deletions airflow-ctl/docs/images/output_tasks.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions airflow-ctl/src/airflowctl/ctl/cli_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,22 @@ def merge_commands(
ARG_MAP_INDEX,
),
),
ActionCommand(
name="state",
help="Get the state of a task instance",
description=(
"Get the state of a task instance. "
"Select the run with either run_id or --logical-date (pass exactly one)."
),
func=lazy_load_command("airflowctl.ctl.commands.task_command.state"),
args=(
ARG_DAG_ID,
ARG_TASK_ID,
ARG_RUN_ID,
ARG_LOGICAL_DATE,
ARG_MAP_INDEX,
),
),
ActionCommand(
name="states-for-dag-run",
help="Get the status of all task instances in a Dag run",
Expand Down
41 changes: 38 additions & 3 deletions airflow-ctl/src/airflowctl/ctl/commands/task_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ def _find_run_id_by_logical_date(api_client, dag_id: str, value: str) -> str:
return dag_runs[0].dag_run_id


def _task_instance_not_found_message(dag_id: str, run_id: str, task_id: str, map_index: int) -> str:
"""Build the message shown when a task instance is not found."""
map_index_part = f" with map index {map_index}" if map_index >= 0 else ""
return (
f"Task instance for task {task_id!r}{map_index_part} in Dag run "
f"{run_id!r} of Dag {dag_id!r} not found"
)


def _format_task_instance(ti: TaskInstanceResponse, has_mapped_instances: bool) -> dict[str, str]:
data = {
"dag_id": ti.dag_id,
Expand Down Expand Up @@ -109,10 +118,8 @@ def failed_deps(args, api_client=NEW_API_CLIENT) -> None:
)
except ServerResponseError as e:
if e.response.status_code == 404:
map_index_part = f" with map index {args.map_index}" if args.map_index >= 0 else ""
rich.print(
f"[red]Task instance for task {args.task_id!r}{map_index_part} in Dag run "
f"{run_id!r} of Dag {args.dag_id!r} not found[/red]"
f"[red]{_task_instance_not_found_message(args.dag_id, run_id, args.task_id, args.map_index)}[/red]"
)
sys.exit(1)
raise
Expand Down Expand Up @@ -149,3 +156,31 @@ def states_for_dag_run(args, api_client=NEW_API_CLIENT) -> None:
data=[_format_task_instance(ti, has_mapped_instances) for ti in task_instances],
output=args.output,
)


@provide_api_client(kind=ClientKind.CLI)
def state(args, api_client=NEW_API_CLIENT) -> None:
"""Get the state of a task instance."""
if (args.run_id is None) == (args.logical_date is None):
rich.print("[red]Provide either run_id or --logical-date, but not both[/red]")
sys.exit(1)

run_id = args.run_id or _find_run_id_by_logical_date(api_client, args.dag_id, args.logical_date)

try:
task_instance = api_client.task_instances.get(
dag_id=args.dag_id,
dag_run_id=run_id,
task_id=args.task_id,
map_index=args.map_index,
suppress_error_log=True,
)
except ServerResponseError as e:
if e.response.status_code == 404:
rich.print(
f"[red]{_task_instance_not_found_message(args.dag_id, run_id, args.task_id, args.map_index)}[/red]"
)
sys.exit(1)
raise

print(task_instance.state.value if task_instance.state else None)
Loading