Files
distributed-execution/src/distributed_execution/tightly_coupled/jobs.py
ILay ccc2e94c2a [SIMPL-30451] Fan out work units so the execution target is observable
The reference graph processed every work unit inside a single op, so exactly one worker was ever reported regardless of executor. That made the guide's claim that k8s_job_executor yields several distinct contributing_hosts false, and left the reference implementations unable to demonstrate the executor choice at all. generate_work_units is now a DynamicOut and both graphs map over it, so one step is created per unit and the loosely coupled pattern dispatches one external workload per unit.

Evidence is split into contributing_workers (host and pid, differs per process) and contributing_hosts (differs only across machines), because the previous single field could not distinguish multiprocess fan-out from no fan-out. Tests now assert the mapped step keys rather than a host count, since execute_in_process ignores executor_def and cannot prove executor behaviour on its own. Adds a Windows note: multiprocess_executor did not complete during authoring and left orphaned processes.

Changelog: fixed
2026-08-26 18:50:01 +02:00

98 lines
3.4 KiB
Python

"""Tightly coupled reference implementations.
Tightly coupled means the process doing the work *is* a Dagster process: it
imports the code location, connects to the metadata database and writes run
events directly. Every execution pod therefore needs network reachability to the
orchestration runtime dependencies.
Three jobs are provided, differing only in their ``executor_def``. That single
construct is the code-level half of the execution-target binding; the other half
is the instance-level run launcher (see ``yaml/tightly-coupled/``).
"""
from __future__ import annotations
from dagster import graph, in_process_executor, multiprocess_executor
from dagster_k8s import k8s_job_executor
from distributed_execution.ops import (
generate_work_units,
process_work_unit,
report_execution_target,
summarise_results,
)
# Applied to run pods by the K8sRunLauncher; surfaces in the Dagster UI run tags.
COMMON_TAGS = {
"execution_target": "tightly_coupled",
"business_operation": "DISTRIBUTED_EXECUTION_REFERENCE",
}
# Per-step pod shape. Only honoured by k8s_job_executor.
STEP_K8S_CONFIG = {
"container_config": {
"resources": {
"requests": {"cpu": "100m", "memory": "128Mi"},
"limits": {"cpu": "500m", "memory": "512Mi"},
},
},
"pod_spec_config": {
"restart_policy": "Never",
},
}
@graph
def distributed_execution_reference():
"""Shared topology, so the three jobs differ only by execution target."""
target_report = report_execution_target()
units = generate_work_units()
results = units.map(process_work_unit).collect()
return summarise_results(results, target_report)
# 1. Single process. Steps run inside the run worker itself - no fan-out at all.
tightly_coupled_in_process_job = distributed_execution_reference.to_job(
name="tightly_coupled_in_process_job",
description=(
"Tightly coupled, single-process. Steps execute inside the run worker. "
"Runs unchanged on a laptop and in Kubernetes."
),
executor_def=in_process_executor,
tags={**COMMON_TAGS, "executor": "in_process"},
)
# 2. Subprocesses on the run worker. Fan-out bounded by that one pod's resources.
tightly_coupled_local_job = distributed_execution_reference.to_job(
name="tightly_coupled_local_job",
description=(
"Tightly coupled, multiprocess. Steps execute as subprocesses of the run worker; "
"concurrency is bounded by the run pod's CPU and memory limits."
),
executor_def=multiprocess_executor.configured({"max_concurrent": 2}),
tags={**COMMON_TAGS, "executor": "multiprocess"},
)
# 3. One Kubernetes Job per step. Requires a cluster; each step pod connects to
# the metadata database on its own, which is what makes this tightly coupled.
tightly_coupled_k8s_job = distributed_execution_reference.to_job(
name="tightly_coupled_k8s_job",
description=(
"Tightly coupled, one Kubernetes Job per step. Each step pod must reach the metadata "
"database, object storage and Vault. Requires a cluster - not runnable locally."
),
executor_def=k8s_job_executor.configured(
{
"image_pull_policy": "IfNotPresent",
"step_k8s_config": STEP_K8S_CONFIG,
}
),
tags={**COMMON_TAGS, "executor": "k8s_job"},
)
TIGHTLY_COUPLED_JOBS = [
tightly_coupled_in_process_job,
tightly_coupled_local_job,
tightly_coupled_k8s_job,
]