Merge pull request '[SIMPL-30451] Distributed execution reference service and container-cluster configuration guide' (#1) from feature/SIMPL-30451-distributed-execution into develop

This commit was merged in pull request #1.
This commit is contained in:
2026-09-02 17:38:22 +00:00
28 changed files with 1248 additions and 500 deletions

View File

@@ -1,151 +0,0 @@
name: Build and Push Docker Images
on:
push:
branches:
- main
workflow_dispatch:
env:
BASE_DOMAIN: dataprovider01.sandbox-cat-dat.simpl-europe.eu
OWNER: j.r
jobs:
build-and-push:
runs-on: orchestration-platform
defaults:
run:
shell: sh
env:
REGISTRY: gitea.${{ env.BASE_DOMAIN }}
IMAGE_REPO: gitea.${{ env.BASE_DOMAIN }}/${{ env.OWNER }}/distributed-execution
PAYLOAD_IMAGE_REPO: gitea.${{ env.BASE_DOMAIN }}/${{ env.OWNER }}/distributed-execution-payload
REPO_DIR: repo
REPO_CLONE_URL: https://gitea.${{ env.BASE_DOMAIN }}/${{ env.OWNER }}/distributed-execution.git
steps:
- name: Checkout repository (shell)
run: |
CLONE_USER="${{ secrets.REGISTRY_USERNAME }}"
CLONE_PASS="${{ secrets.REGISTRY_PASSWORD }}"
REF_NAME="${GITHUB_REF_NAME}"
if [ -z "${REF_NAME}" ]; then
REF_NAME="${GITHUB_REF#refs/heads/}"
fi
if [ -z "${CLONE_USER}" ] || [ -z "${CLONE_PASS}" ]; then
echo "Missing REGISTRY_USERNAME or REGISTRY_PASSWORD secret"
exit 1
fi
rm -rf "${REPO_DIR}"
AUTH_HEADER="$(printf '%s:%s' "${CLONE_USER}" "${CLONE_PASS}" | base64 | tr -d '\n')"
git clone --depth 1 --branch "${REF_NAME}" \
-c "http.extraHeader=Authorization: Basic ${AUTH_HEADER}" \
"${REPO_CLONE_URL}" \
"${REPO_DIR}"
if [ ! -f "${REPO_DIR}/Dockerfile" ]; then
echo "Code location Dockerfile not found after clone"
exit 1
fi
if [ ! -f "${REPO_DIR}/payload/Dockerfile" ]; then
echo "Payload Dockerfile not found after clone"
exit 1
fi
- name: Validate registry secrets
run: |
if [ -z "${{ secrets.REGISTRY_USERNAME }}" ] || [ -z "${{ secrets.REGISTRY_PASSWORD }}" ]; then
echo "Missing REGISTRY_USERNAME or REGISTRY_PASSWORD secret"
exit 1
fi
- name: Login to registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${REGISTRY}" \
-u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
# Both images take the same SHA tag: that is what keeps the code location and
# the payload it dispatches on the same version.
- name: Build code location image
run: |
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
cd "${REPO_DIR}"
docker build \
-t "${IMAGE_REPO}:latest" \
-t "${IMAGE_REPO}:${SHORT_SHA}" \
.
- name: Build payload image
run: |
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
cd "${REPO_DIR}"
docker build \
-f payload/Dockerfile \
-t "${PAYLOAD_IMAGE_REPO}:latest" \
-t "${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}" \
payload/
- name: Validate code location image
run: |
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
docker run --rm "${IMAGE_REPO}:${SHORT_SHA}" \
dagster definitions validate -f src/distributed_execution/repository.py
docker run --rm "${IMAGE_REPO}:${SHORT_SHA}" \
test -f /app/payload/work.py
# Readiness checklist L11: the payload image must not carry the orchestration
# runtime, otherwise the isolation argument for the loosely coupled target is void.
- name: Validate payload image isolation
run: |
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
docker run --rm "${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}" python -c "
import importlib.util
assert importlib.util.find_spec('dagster_pipes') is not None, 'dagster_pipes missing from payload image'
assert importlib.util.find_spec('dagster') is None, 'payload image must not contain the dagster package'
print('payload isolation OK')
"
- name: Push code location image tags
run: |
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
docker push "${IMAGE_REPO}:latest"
docker push "${IMAGE_REPO}:${SHORT_SHA}"
- name: Push payload image tags
run: |
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
docker push "${PAYLOAD_IMAGE_REPO}:latest"
docker push "${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}"
- name: Report image references
run: |
COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
echo "Code location image: ${IMAGE_REPO}:${SHORT_SHA}"
echo "Payload image: ${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}"
echo ""
echo "Set PIPES_PAYLOAD_IMAGE on both the code location and the run pods:"
echo " PIPES_PAYLOAD_IMAGE=${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}"
echo "See yaml/loosely-coupled/values-pipes-payload.yaml."
# The automated update of the deployment requires a technical user with
# their kube config in the secrets. See the template repository's user manual.
# - name: Update Dagster user deployment image
# run: |
# COMMIT_SHA="${GITHUB_SHA:-$GITEA_SHA}"
# SHORT_SHA="$(echo "${COMMIT_SHA}" | cut -c1-12)"
# kubectl patch deployment "${DEPLOYMENT_NAME}" \
# -n "${K8S_NAMESPACE}" \
# --type='strategic' \
# -p="{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"dagster-user-deployments\",\"image\":\"${IMAGE_REPO}:${SHORT_SHA}\",\"env\":[{\"name\":\"DAGSTER_CURRENT_IMAGE\",\"value\":\"${IMAGE_REPO}:${SHORT_SHA}\"},{\"name\":\"PIPES_PAYLOAD_IMAGE\",\"value\":\"${PAYLOAD_IMAGE_REPO}:${SHORT_SHA}\"}]}]}}}}"
# kubectl rollout status deployment/"${DEPLOYMENT_NAME}" \
# -n "${K8S_NAMESPACE}" \
# --timeout=5m

View File

@@ -1,3 +1 @@
# All subgroup members as Code Owners for all files * @simpl/simpl-users/sc1/codeowners/data-supporting-data-services-distributed-execution-distributed-execution
* @simpl/simpl-open/data/supporting-data-services

View File

@@ -4,15 +4,33 @@
- Repository skeleton for the `distributed-execution` supporting data service. - Repository skeleton for the `distributed-execution` supporting data service.
- User guide covering execution-target selection, decision support and readiness checks. - User guide covering execution-target selection, decision support and readiness checks.
- Cluster-configuration input reference: mandatory versus optional inputs per setup,
a reusable minimum input set and worked examples in both setups' own formats.
- Requirement traceability mapping the guide's sections onto SIMPL-30451 and SIMPL-30787.
- Runnable tightly coupled reference implementations (`in_process`, `multiprocess`, `k8s_job_executor`). - Runnable tightly coupled reference implementations (`in_process`, `multiprocess`, `k8s_job_executor`).
- Runnable loosely coupled reference implementations via dagster-pipes - Runnable loosely coupled reference implementations via dagster-pipes
(`PipesSubprocessClient`, `PipesK8sClient`) with a standalone external payload image. (`PipesSubprocessClient`, `PipesK8sClient`) with a standalone external payload image.
- Working example configuration and RBAC for both execution targets. - Working example configuration and RBAC for both execution targets.
### verified
- `tightly_coupled_k8s_job` executed end to end on sandbox-cat-dat through the
platform `K8sRunLauncher` (run `1d8cb167-9fb8-4a34-a036-789eac381e13`), closing
readiness rows T6 and T7. Step outputs are written to the shared
`dagster-shared-pvc` by pinning `fs_io_manager`'s `base_dir`; `DAGSTER_HOME` set
through `step_k8s_config` is ignored, because the Dagster chart injects
`DAGSTER_HOME=/tmp/dagster` ahead of it.
- `loosely_coupled_k8s_job` reached `RUN_SUCCESS` on sandbox-cat-dat through the
standalone probe (run `cff9b348-bfc3-4ac1-ab51-a94892b8e3a0`), with four
external payload pods reporting over the pod-log message channel.
- Tightly coupled preflight evidence now checks the chart's actual
`DAGSTER_PG_PASSWORD` injection without exposing its value.
- Dagster UI screenshots cover the registered jobs, graph, code-configured
execution-target tags and a successful reference run.
- The platform deployment diagram includes the service and both integration
patterns.
### pending ### pending
- Publish the payload image to the container registry. - Extend the project-level GitLab pipeline to publish the payload image as well
- End-to-end run of `loosely_coupled_k8s_job` against a cluster, and confirmation as the code-location image.
of the Kubernetes rows in the readiness checklist.
- Screenshots of UI surfaces and integration-pattern diagrams.
- Platform architecture document update.

View File

@@ -1,3 +1,3 @@
# EUROPEAN UNION PUBLIC LICENCE v. 1.2 # EUROPEAN UNION PUBLIC LICENSE v. 1.2
Refer to [licence description](https://eupl.eu/1.2/en/) Refer to [license description](https://eupl.eu/1.2/en/)

View File

@@ -14,7 +14,7 @@ actually run, and how does runtime information get back to the control plane?*
| User guide | [documents/user-guide/distributed-execution-guide.md](documents/user-guide/distributed-execution-guide.md) | Complete | | User guide | [documents/user-guide/distributed-execution-guide.md](documents/user-guide/distributed-execution-guide.md) | Complete |
| Readiness checklist | [documents/user-guide/readiness-checklist.md](documents/user-guide/readiness-checklist.md) | Complete | | Readiness checklist | [documents/user-guide/readiness-checklist.md](documents/user-guide/readiness-checklist.md) | Complete |
| Tightly coupled reference | [src/distributed_execution/tightly_coupled/jobs.py](src/distributed_execution/tightly_coupled/jobs.py) | Runnable | | Tightly coupled reference | [src/distributed_execution/tightly_coupled/jobs.py](src/distributed_execution/tightly_coupled/jobs.py) | Runnable |
| Loosely coupled reference | [src/distributed_execution/loosely_coupled/jobs.py](src/distributed_execution/loosely_coupled/jobs.py) | Runnable (subprocess verified) | | Loosely coupled reference | [src/distributed_execution/loosely_coupled/jobs.py](src/distributed_execution/loosely_coupled/jobs.py) | Runnable and cluster-verified |
| External payload | [payload/work.py](payload/work.py) | Runnable | | External payload | [payload/work.py](payload/work.py) | Runnable |
| Example configuration | [yaml/](yaml/) | Complete | | Example configuration | [yaml/](yaml/) | Complete |
@@ -35,7 +35,7 @@ distributed-execution/
│ ├── work.py │ ├── work.py
│ ├── requirements.txt │ ├── requirements.txt
│ └── Dockerfile │ └── Dockerfile
├── documents/user-guide/ # AC1-AC4 documentation ├── documents/user-guide/ # Guide, checklist and requirement traceability
├── yaml/ # Working example configuration ├── yaml/ # Working example configuration
├── tests/ ├── tests/
├── Dockerfile ├── Dockerfile
@@ -81,17 +81,17 @@ Both images build and have been smoke tested locally: the code location image
loads its definitions, and the payload image contains `dagster_pipes` without loads its definitions, and the payload image contains `dagster_pipes` without
`dagster` — check L11 in the readiness checklist. `dagster` — check L11 in the readiness checklist.
[.gitea/workflows/docker-publish.yml](.gitea/workflows/docker-publish.yml) runs Both must be tagged from the same commit. That shared tag is what keeps a code
the same two builds on every push to `main`, applies those checks as gates, and location and the payload it dispatches on the same version, and nothing at
tags both images with the same short commit SHA — that shared tag is what keeps a runtime checks the pairing — see the *Outstanding work* section for what the
code location and the payload it dispatches on the same version. pipeline still has to learn.
## Status ## Status
Both execution targets are implemented. The tightly coupled jobs and the loosely Both execution targets are implemented. Local variants are verified by the test
coupled **subprocess** transport are verified by the test suite. The loosely suite, `tightly_coupled_k8s_job` has run end to end through the platform launcher,
coupled **Kubernetes** transport is implemented but has not yet been run against and `loosely_coupled_k8s_job` has run end to end through the standalone cluster
a cluster; see the guide's *Outstanding work* section. probe. See the guide and readiness checklist for the recorded evidence.
## Licence ## Licence

View File

@@ -5,12 +5,10 @@
integration pattern for a Dagster workflow on the Simpl orchestration platform. integration pattern for a Dagster workflow on the Simpl orchestration platform.
> **Document status.** Both setups are backed by runnable reference > **Document status.** Both setups are backed by runnable reference
> implementations in this repository. The tightly coupled setup and the loosely > implementations and verified end to end. The loosely coupled Kubernetes path
> coupled **subprocess** transport are verified end to end, including runs > reached `RUN_SUCCESS` on sandbox-cat-dat on 2026-08-31; the tightly coupled
> launched from the Dagster UI — see [section 5.6](#56-what-a-verified-run-actually-produced). > `k8s_job_executor` path reached `RUN_SUCCESS` through the platform launcher on
> The loosely coupled **Kubernetes** transport is implemented and reviewed but > 2026-09-01. See the readiness checklist for the recorded evidence.
> has not yet been run against a cluster; statements specific to it are marked
> **NOT CLUSTER-VERIFIED**. See [Outstanding work](#8-outstanding-work).
--- ---
@@ -68,7 +66,7 @@ pattern.
--- ---
## 2. AC1 — Choosing an execution target ## 2. Choosing an execution target and cluster setup
### 2.1 Choose tightly coupled when ### 2.1 Choose tightly coupled when
@@ -123,7 +121,7 @@ before it is run for the first time. Section 5.4 explains where each item lives.
--- ---
## 3. AC2 — Decision support ## 3. Decision support and cluster-configuration inputs
### 3.1 Side-by-side comparison ### 3.1 Side-by-side comparison
@@ -181,9 +179,134 @@ Use these as a fast triage. If several point the same way, that is your answer.
succeed while reporting nothing. Two images to build, version and scan instead succeed while reporting nothing. Two images to build, version and scan instead
of one. of one.
### 3.4 Cluster-configuration inputs
Once the setup is chosen, the container cluster has to be described. The table
below is the full input surface, split into what a run cannot start without and
what only applies under a stated condition. "Mandatory" means the run fails, or
reports nothing, if the input is absent or wrong.
| Input | Tightly coupled | Loosely coupled | Notes |
|---|---|---|---|
| Cluster / kube context hosting the run worker | Mandatory | Mandatory | The launcher's cluster. Loosely coupled may dispatch to a *second* cluster |
| Namespace for run pods | Mandatory | Mandatory | Supplied by the code location's `DAGSTER_CONTAINER_CONTEXT`; the launcher's `job_namespace` is only a fallback |
| Code location image reference and tag | Mandatory | Mandatory | Never `latest`; check C3 |
| Executor selection | Mandatory | Mandatory | Bounds step granularity; loosely coupled it bounds only dispatch concurrency |
| Service account for run pods | Mandatory | Mandatory | Must have `automountServiceAccountToken: true` |
| Run-pod egress to the metadata database | **Mandatory** | Not applicable | The pod that writes run events |
| Namespace for step pods | Conditional — `k8s_job_executor` only | Not applicable | Defaults to the run pod's namespace |
| RBAC to create and watch Jobs | Conditional — `k8s_job_executor` only | **Mandatory**, in the payload namespace | Same verbs, different namespace |
| Shared RWX volume plus an I/O manager `base_dir` under it | Conditional — `k8s_job_executor` only | Optional | Without it step pods cannot read each other's outputs |
| Per-step resource requests and limits | Optional | Optional | Multiply by step or dispatch concurrency |
| Payload image reference and tag | Not applicable | **Mandatory** | Must share the code location's commit tag |
| Namespace for payload workloads | Not applicable | **Mandatory** | May be in another cluster or trust boundary |
| Message channel and its reader | Not applicable | **Mandatory** | Pod log stream by default; RBAC on `pods/log` *is* the channel |
| Payload wait timeout | Not applicable | Optional | Defaults to 24 h — lower it so scheduling failures surface |
| Vault role and secret paths | Conditional — if the workflow reads secrets | Conditional — launching pod only | Payloads should receive only `extras` and explicit `env` |
| Object-storage endpoint and credentials | Conditional — if the workflow uses S3 | Conditional — if the *payload* uses S3 | |
| Image pull secret | Conditional — non-anonymous registry | Conditional — non-anonymous registry | Applies to the SA that runs the pod, which for dispatched payload Jobs is `default` |
### 3.5 Minimum input set
The list below is the reusable baseline: the smallest set of values a team has to
agree on before a workflow can be configured against a cluster. Record it once
per workflow, in the workflow's own repository, and carry it into whatever
configuration format the team already uses.
**Both setups**
1. `cluster` — the cluster the run worker lands in.
2. `run_namespace` — namespace for run pods.
3. `code_location_image` — image reference including an immutable tag.
4. `executor` — executor name plus its concurrency bound.
5. `service_account` — the identity run pods assume.
**Tightly coupled adds**
6. `metadata_db` — host and port the run and step pods must reach.
7. `step_namespace` — only when `k8s_job_executor` is used.
8. `shared_output_path` — RWX mount path, and the I/O manager `base_dir` pinned
under it, again only for `k8s_job_executor`.
**Loosely coupled adds**
6. `payload_image` — image reference sharing the code location's commit tag.
7. `payload_namespace` — where dispatched workloads are created; may be in
another cluster.
8. `message_channel` — the reader in use, and the RBAC verb that carries it.
This guide deliberately does **not** prescribe a configuration schema or key
names. The names above are descriptive labels for the values, not a required
format; the examples in section 3.6 express the same baseline in two different
shapes, and both are correct.
### 3.6 Worked input examples
The reference configuration in [yaml/](../../yaml) shows the baseline expressed
in the formats each setup already uses. Neither is normative.
**Tightly coupled** — the inputs land in Helm values and in the job's executor
config, because that is where the platform chart and Dagster expect them:
```yaml
# yaml/tightly-coupled/values-run-launcher.yaml (shape, not a fixed schema)
dagster:
runLauncher:
type: K8sRunLauncher
config:
k8sRunLauncher:
jobNamespace: dagster # run_namespace
failPodOnRunFailure: true
runK8sConfig:
containerConfig:
env: # metadata_db, S3 and Vault reachability
- name: S3_ENDPOINT_URL
value: https://s3.dev.simpl-europe.eu
```
```python
# step_namespace, shared_output_path and the executor travel with the job
tightly_coupled_k8s_job = distributed_execution_reference.to_job(
executor_def=k8s_job_executor,
resource_defs={"io_manager": fs_io_manager.configured({"base_dir": SHARED_IO_BASE_DIR})},
config={"execution": {"config": {"step_k8s_config": STEP_K8S_CONFIG}}},
)
```
**Loosely coupled** — the same baseline, but the cluster-facing half is the
payload image and its namespace. Here they are environment values set on both the
code location and the run launcher, because the dispatching pod is a run pod:
```yaml
# yaml/loosely-coupled/values-pipes-payload.yaml (shape, not a fixed schema)
dagster:
dagster-user-deployments:
deployments:
- name: distributed-execution
env:
- name: PIPES_PAYLOAD_IMAGE # payload_image, tag-locked
value: <registry>/distributed-execution/payload:0.0.0
- name: PIPES_PAYLOAD_NAMESPACE # payload_namespace
value: dagster
```
```python
PAYLOAD_IMAGE = os.environ.get("PIPES_PAYLOAD_IMAGE", ...)
PAYLOAD_NAMESPACE = os.environ.get("PIPES_PAYLOAD_NAMESPACE", "dagster")
```
The `message_channel` input has no key in either file. The default reader is the
pod log stream, so it is configured by granting `pods/log` in
[yaml/loosely-coupled/rbac-pipes-dispatch.yaml](../../yaml/loosely-coupled/rbac-pipes-dispatch.yaml).
An input can be mandatory and still not be a configuration field.
Note what is absent from the loosely coupled example: no metadata database, no
Vault role, no object-storage credentials. Those inputs are not optional there —
they do not exist, which is the operational consequence of the choice.
--- ---
## 4. AC3 — Readiness checks ## 4. Readiness checks
Pre-run validation items, their expected evidence, and the symptoms and Pre-run validation items, their expected evidence, and the symptoms and
corrections for common misconfigurations are maintained separately, in corrections for common misconfigurations are maintained separately, in
@@ -191,7 +314,7 @@ corrections for common misconfigurations are maintained separately, in
--- ---
## 5. AC4 — Configuring execution-target linkage in code ## 5. Configuring execution-target linkage in code
### 5.1 Configuration constructs ### 5.1 Configuration constructs
@@ -231,12 +354,18 @@ tightly_coupled_local_job = distributed_execution_reference.to_job(
```python ```python
tightly_coupled_k8s_job = distributed_execution_reference.to_job( tightly_coupled_k8s_job = distributed_execution_reference.to_job(
name="tightly_coupled_k8s_job", name="tightly_coupled_k8s_job",
executor_def=k8s_job_executor.configured( executor_def=k8s_job_executor,
{ resource_defs={
"io_manager": fs_io_manager.configured({"base_dir": SHARED_IO_BASE_DIR})
},
config={
"execution": {
"config": {
"image_pull_policy": "IfNotPresent", "image_pull_policy": "IfNotPresent",
"step_k8s_config": STEP_K8S_CONFIG, "step_k8s_config": STEP_K8S_CONFIG,
} }
), }
},
tags={**COMMON_TAGS, "executor": "k8s_job"}, tags={**COMMON_TAGS, "executor": "k8s_job"},
) )
``` ```
@@ -251,6 +380,22 @@ operationally:
[yaml/tightly-coupled/rbac-step-executor.yaml](../../yaml/tightly-coupled/rbac-step-executor.yaml). [yaml/tightly-coupled/rbac-step-executor.yaml](../../yaml/tightly-coupled/rbac-step-executor.yaml).
- Per-step resource requests apply per pod, so the aggregate request for a - Per-step resource requests apply per pod, so the aggregate request for a
fan-out step is the per-step request multiplied by concurrency. fan-out step is the per-step request multiplied by concurrency.
- **Step outputs must land on storage every step pod can read.** With the default
filesystem I/O manager each pod writes to its own container filesystem, so a
downstream step opens a path that does not exist there. `STEP_K8S_CONFIG` mounts
the RWX `dagster-shared-pvc` at `/dagster/shared`, and the job pins
`fs_io_manager`'s `base_dir` underneath it.
- Pin `base_dir` directly rather than relying on `DAGSTER_HOME`. The default
`base_dir` is `$DAGSTER_HOME/storage`, but the Dagster chart already injects
`DAGSTER_HOME=/tmp/dagster` into the step container; a second entry appended by
`step_k8s_config` does not displace it, so the override is silently ignored and
outputs keep going to `/tmp/dagster/storage`.
The executor's defaults go through `config=` rather than
`k8s_job_executor.configured(...)`. `.configured()` collapses the executor's
config schema to `Any`, which makes a run-config `execution:` block accepted and
then discarded, and makes `job_image` and `job_namespace` impossible to supply at
launch time.
The evidence that the switch took effect is in `summarise_results` output The evidence that the switch took effect is in `summarise_results` output
metadata, and the two fields say different things: metadata, and the two fields say different things:
@@ -378,10 +523,12 @@ empty result. If your cluster's logging setup makes that transport unreliable,
switch to an object-storage message reader, which needs a bucket plus switch to an object-storage message reader, which needs a bucket plus
credentials on both sides. credentials on both sides.
> **NOT CLUSTER-VERIFIED.** The Kubernetes transport above is implemented and > **CLUSTER-VERIFIED 2026-08-31.** Run `cff9b348…` of `loosely_coupled_k8s_job`
> its RBAC and configuration are recorded, but it has not yet been run against a > reached `RUN_SUCCESS` on sandbox-cat-dat. Four payload Jobs were created, one
> Simpl cluster. The subprocess transport, which exercises the identical payload > per work unit, and `contributing_hosts` held four distinct payload pod names —
> and the identical message-parsing path, is verified by the test suite. > so the work demonstrably ran off the orchestrator. The payload's log lines
> reached the run log, which is the pod log stream serving as the message
> channel exactly as described above.
### 5.4 Where setup selection is persisted ### 5.4 Where setup selection is persisted
@@ -395,7 +542,10 @@ setting. There is no UI control that switches a workflow between the two pattern
| `yaml/tightly-coupled/values-run-launcher.yaml` | Run launcher type, namespace, pod env | | `yaml/tightly-coupled/values-run-launcher.yaml` | Run launcher type, namespace, pod env |
| `yaml/tightly-coupled/rbac-step-executor.yaml` | Permissions required by `k8s_job_executor` | | `yaml/tightly-coupled/rbac-step-executor.yaml` | Permissions required by `k8s_job_executor` |
| `yaml/loosely-coupled/values-pipes-payload.yaml` | Payload image reference and target namespace | | `yaml/loosely-coupled/values-pipes-payload.yaml` | Payload image reference and target namespace |
| `yaml/sandbox/values-sandbox-gitea.yaml` | Sandbox registry coordinates, pull secret, and the SHA both images share |
| `yaml/loosely-coupled/rbac-pipes-dispatch.yaml` | Permissions required by the dispatching pod | | `yaml/loosely-coupled/rbac-pipes-dispatch.yaml` | Permissions required by the dispatching pod |
| `yaml/loosely-coupled/probe-pipes-k8s.yaml` | Standalone cluster probe for the pipes transport (checklist L4L9) |
| `yaml/sandbox/probe-pipes-k8s-sandbox.yaml` | The same probe for sandbox-cat-dat, where project-scoped access forbids creating namespaces and RBAC |
| `yaml/values-dagster-distributed-execution.yaml` | Code location image and entry point | | `yaml/values-dagster-distributed-execution.yaml` | Code location image and entry point |
The Launchpad can override *run configuration* — op config, resource config, tags The Launchpad can override *run configuration* — op config, resource config, tags
@@ -478,6 +628,32 @@ on a cluster it is what distinguishes `k8s_job_executor` from
holds the namespace the run pod landed in, which is the placement half of the holds the namespace the run pod landed in, which is the placement half of the
execution target. execution target.
### 5.7 Dagster UI reference
The screenshots below were captured from the local reference service on
2026-09-02. They show the surfaces participants use to inspect job linkage and
run evidence. Cluster placement is evidenced separately by the sandbox run IDs
in the readiness checklist.
All five reference jobs are registered under one code location:
![Distributed execution job list](images/distributed-execution-job-list.png)
The job overview exposes the graph whose executor or dispatch op defines the
integration pattern:
![Tightly coupled reference graph](images/distributed-execution-job-graph.png)
The Launchpad shows that `execution_target` and `executor` are job tags persisted
by code configuration, not a separate runtime-only selector:
![Execution-target tags in Launchpad](images/distributed-execution-launchpad.png)
A successful local run displays the step events and final status used alongside
output metadata as retained evidence:
![Successful tightly coupled reference run](images/distributed-execution-successful-run.png)
--- ---
## 6. Upstream documentation ## 6. Upstream documentation
@@ -499,22 +675,59 @@ execution target.
## 8. Outstanding work ## 8. Outstanding work
Tracked under SIMPL-30451. Tracked under SIMPL-30451 and SIMPL-30787.
| Item | AC | Status | | Item | Status |
|---|---|
| Execution-target choices, prerequisites, workflow-level documentation | Complete |
| Comparison, environment-fit indicators, trade-offs | Complete |
| Cluster-configuration inputs, mandatory vs optional, minimum input set | Complete |
| Readiness checklist and evidence mapping | Complete; both Kubernetes paths cluster-verified |
| Misconfiguration symptoms and corrections | Complete; corrected with observed cluster failure modes |
| Configuration constructs and persistence | Complete |
| Before-and-after example, tightly coupled | Complete |
| Before-and-after example, switching to loosely coupled | Complete |
| Runnable tightly coupled reference implementations | Complete |
| Runnable loosely coupled reference implementation | Complete (subprocess and Kubernetes transports both verified) |
| Both images build; payload image passes the isolation check (L11) | Complete |
| Locally runnable jobs launched from the Dagster UI, evidence recorded in section 5.6 | Complete |
| Payload image published to a container registry | Complete on the sandbox Gitea registry; the GitLab registry still pending |
| GitLab pipeline builds both images | **Pending** — the shared `ds.gitlab-ci.yml` template builds one image from the root Dockerfile |
| End-to-end run of `loosely_coupled_k8s_job` on a cluster | Complete — sandbox-cat-dat, 2026-08-31, run `cff9b348…`; see the readiness checklist |
| `distributed-execution` registered as a code location on a platform Dagster | Complete — tightly coupled run `1d8cb167…` launched through the platform webserver |
| Screenshots of UI surfaces | Complete — job list, graph, Launchpad linkage and successful run captured in section 5.7 |
| Platform architecture document update | Complete — root `deployment_diagram.md` includes the service and both runtime-information paths |
---
## 9. Requirement traceability
The sections above are organised by subject, not by ticket. Two stories share
this material; the mapping below is authoritative for both.
### SIMPL-30787 — defining the execution container cluster
| AC | Requirement | Where it is met |
|---|---|---| |---|---|---|
| Execution-target choices, prerequisites, workflow-level documentation | AC1 | Complete | | AC1 | Prerequisites for both setups | Section 2.3 |
| Comparison, environment-fit indicators, trade-offs | AC2 | Complete | | AC1 | What must be documented before execution | Section 2.4 |
| Readiness checklist and evidence mapping | AC3 | Complete; K8s pipes checks not cluster-verified | | AC1 | Where cluster-runtime connectivity is required, where decoupled reporting is expected | Sections 1.2 and 2.3; the asymmetry is drawn in the section 1.2 diagram |
| Misconfiguration symptoms and corrections | AC3 | Complete; K8s pipes symptoms not cluster-verified | | AC2 | Mandatory vs optional inputs per setup | Section 3.4 |
| Configuration constructs and persistence | AC4 | Complete | | AC2 | Examples for both setups, no fixed config naming model | Section 3.6, with the closing note in 3.5 |
| Before-and-after example, tightly coupled | AC4 | Complete | | AC2 | Reusable minimum input set | Section 3.5 |
| Before-and-after example, switching to loosely coupled | AC4 | Complete | | AC3 | Checklist separates tightly from loosely coupled checks | [readiness-checklist.md](readiness-checklist.md) sections 2 and 3; section 1 holds the checks common to both |
| Runnable tightly coupled reference implementations | AC4 | Complete | | AC3 | Each item mapped to expected evidence | The *Expected evidence* column of every checklist table |
| Runnable loosely coupled reference implementation | AC4 | Complete (subprocess verified, K8s not cluster-run) | | AC4 | Configuration constructs attaching the pattern to a workflow | Section 5.1 |
| Both images build; payload image passes the isolation check (L11) | Tech details | Complete | | AC4 | Worked before-and-after example across setups | Sections 5.2 and 5.3 |
| Locally runnable jobs launched from the Dagster UI, evidence recorded in section 5.6 | Tech details | Complete | | AC4 | At least one runnable reference implementation per setup | Section 5.5 — three tightly coupled, two loosely coupled |
| Payload image published to a container registry | Tech details | Complete on the sandbox Gitea registry; the GitLab registry still pending | | AC4 | Selection persisted in configuration artifacts, not runtime-only | Section 5.4 |
| End-to-end run of `loosely_coupled_k8s_job` on a cluster | Tech details | **Pending** | | Tech | Diagrams, screenshots, working config files, upstream links | Sections 1.2, 5.7, [yaml/](../../yaml), section 6 |
| Screenshots of UI surfaces | Tech details | **Pending** — needs a deployed platform instance, not a local dev server |
| Platform architecture document update | Tech details | **Pending** | ### SIMPL-30451 — execution targets and integration patterns
| AC | Subject | Where it is met |
|---|---|---|
| AC1 | Choosing an execution target | Section 2 |
| AC2 | Decision support | Sections 3.1 to 3.3 |
| AC3 | Readiness checks | Section 4 and the readiness checklist |
| AC4 | Linkage configured in code | Section 5 |

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

View File

@@ -1,17 +1,20 @@
# Distributed Execution: Readiness Checklist # Distributed Execution: Readiness Checklist
Pre-run validation for a workflow's execution target. Companion to the Pre-run validation for a workflow's execution target. Companion to the
[user guide](distributed-execution-guide.md); this document covers AC3. [user guide](distributed-execution-guide.md); this document is the validation
checklist required by SIMPL-30451 AC3 and SIMPL-30787 AC3. Section 1 holds the
checks common to both setups, section 2 the tightly coupled checks and section 3
the loosely coupled ones; every item states the evidence that proves it.
Run these checks **before the first execution** of a workflow, and again after any Run these checks **before the first execution** of a workflow, and again after any
change to the run launcher, the executor, the target namespace or the code change to the run launcher, the executor, the target namespace or the code
location image. location image.
> **NOT CLUSTER-VERIFIED.** Checks L4L9 and the Kubernetes rows of section 4.3 > **Both Kubernetes paths are cluster-verified.** L4L10 were cleared on
> are derived from the implemented reference but have not yet been run against a > sandbox-cat-dat on 2026-08-31. The tightly coupled `k8s_job_executor` path
> Simpl cluster. Checks L1L3, L10 and L11, which exercise the payload contract, > reached `RUN_SUCCESS` through the platform launcher on 2026-09-01. Checks
> the message-parsing path, per-unit dispatch and image-level isolation, are > L1L3 and L11, which exercise the payload contract, message parsing and image
> verified locally. > isolation, are also verified locally. See [section 2.1](#21-sandbox-state-2026-08-31).
--- ---
@@ -23,14 +26,14 @@ location image.
| C2 | Jobs are registered | Dagster UI → **Jobs** | The jobs listed in the guide's section 5.5 appear under the code location | | C2 | Jobs are registered | Dagster UI → **Jobs** | The jobs listed in the guide's section 5.5 appear under the code location |
| C3 | Image tag matches the intended release | `kubectl -n dagster get deploy -l dagster/code-location=distributed-execution -o jsonpath='{.items[*].spec.template.spec.containers[*].image}'` | Tag equals the version in `pipeline.variables.sh`; never `latest` | | C3 | Image tag matches the intended release | `kubectl -n dagster get deploy -l dagster/code-location=distributed-execution -o jsonpath='{.items[*].spec.template.spec.containers[*].image}'` | Tag equals the version in `pipeline.variables.sh`; never `latest` |
| C4 | Image architecture matches the nodes | `docker manifest inspect <image>` | Includes `linux/amd64`; a manifest with only `linux/arm64` produces `no match for platform` at pull time | | C4 | Image architecture matches the nodes | `docker manifest inspect <image>` | Includes `linux/amd64`; a manifest with only `linux/arm64` produces `no match for platform` at pull time |
| C5 | Run launcher type is as intended | `kubectl -n dagster get cm dagster-instance -o yaml` | `run_launcher` block shows `K8sRunLauncher` and the expected `job_namespace` | | C5 | Run launcher type is as intended | `kubectl -n <namespace> get cm dagster-instance -o yaml` | `run_launcher` block shows `K8sRunLauncher`. Note that `job_namespace` here is only a default — a code location's `DAGSTER_CONTAINER_CONTEXT` overrides it, so read that too before concluding where run pods land |
| C6 | Target namespace exists and is schedulable | `kubectl get ns <namespace>` and `kubectl -n <namespace> get resourcequota` | Namespace is `Active`; remaining quota exceeds the job's aggregate requests | | C6 | Target namespace exists and is schedulable | `kubectl get ns <namespace>` and `kubectl -n <namespace> get resourcequota` | Namespace is `Active`; remaining quota exceeds the job's aggregate requests. Also confirm the launcher's `instance_config_map`, `postgres_password_secret` and any PVC volumes exist **in the namespace run pods actually use** — these references do not cross namespaces (see section 2.1) |
## 2. Tightly coupled checks ## 2. Tightly coupled checks
| # | Check | How to verify | Expected evidence | | # | Check | How to verify | Expected evidence |
|---|---|---|---| |---|---|---|---|
| T1 | Run pod reaches the metadata database | Launch `tightly_coupled_in_process_job` | Run reaches `SUCCESS`; `report_execution_target` output metadata lists `DAGSTER_POSTGRES_HOST`, `DAGSTER_POSTGRES_USER` and `DAGSTER_POSTGRES_DB` under `env_vars_present`, and `env_vars_missing` is empty | | T1 | Run pod reaches the metadata database | Launch `tightly_coupled_in_process_job` | Run reaches `SUCCESS`; `report_execution_target` metadata lists `DAGSTER_PG_PASSWORD` under `env_vars_present` without exposing its value, and `env_vars_missing` is empty. Successful step startup is the connectivity proof because the step loads run state from Postgres before executing the op |
| T2 | Vault injection works | Same run; inspect the run pod | `kubectl -n dagster describe pod <run-pod>` shows the `vault-env` init container completed; no `vault:` literal remains in the process environment | | T2 | Vault injection works | Same run; inspect the run pod | `kubectl -n dagster describe pod <run-pod>` shows the `vault-env` init container completed; no `vault:` literal remains in the process environment |
| T3 | Object storage is reachable | Same run, if the workflow uses S3 | No `EndpointConnectionError` in run logs; `S3_ENDPOINT_URL` present in `env_vars_present` | | T3 | Object storage is reachable | Same run, if the workflow uses S3 | No `EndpointConnectionError` in run logs; `S3_ENDPOINT_URL` present in `env_vars_present` |
| T4 | Multiprocess fan-out actually fans out | Launch `tightly_coupled_local_job` | Run succeeds; `summarise_results` metadata shows one entry per unit in `contributing_workers` and a single entry in `contributing_hosts` — separate processes, same machine | | T4 | Multiprocess fan-out actually fans out | Launch `tightly_coupled_local_job` | Run succeeds; `summarise_results` metadata shows one entry per unit in `contributing_workers` and a single entry in `contributing_hosts` — separate processes, same machine |
@@ -39,6 +42,154 @@ location image.
| T7 | Step pod egress is permitted | Same run | Steps do not hang in `STARTING`; run logs contain no connection timeouts to port 5432 | | T7 | Step pod egress is permitted | Same run | Steps do not hang in `STARTING`; run logs contain no connection timeouts to port 5432 |
| T8 | Failure surfaces as a pod failure | Force a step failure in a scratch namespace | `failPodOnRunFailure: true` is set, and the step pod reports `Failed` rather than `Completed` | | T8 | Failure surfaces as a pod failure | Force a step failure in a scratch namespace | `failPodOnRunFailure: true` is set, and the step pod reports `Failed` rather than `Completed` |
### 2.1 Sandbox state, 2026-08-31
The T checks were assessed against sandbox-cat-dat by reading the live
`dagster-instance` ConfigMap in `dataprovider01` and by running T1, T4, T6 and T7
from pods there.
What the configuration shows:
| # | Finding |
|---|---|
| C5 | `run_launcher` is `K8sRunLauncher`; `job_namespace: dagster` is the default, overridden per code location to `dataprovider01` |
| T2 | Vault injection is configured — `pod_template_spec_metadata` carries the banzaicloud annotations with role `sandbox-cat-dat-role` |
| T3 | `S3_ENDPOINT_URL` is `https://s3.sandbox-cat-dat.simpl-europe.eu`, with access keys injected from Vault |
| T5 | Passes. `dagster-role`, bound to `dagster-svc-account`, grants `batch/jobs` with create, delete, get, list, patch, update and watch |
| T8 | `fail_pod_on_run_failure: true` is set |
**T1 and T4 were executed on 2026-08-31** from a pod in `dataprovider01`
(`yaml/sandbox/probe-tightly-coupled-sandbox.yaml`), using a local SQLite
instance rather than the platform's Postgres.
| # | Result |
|---|---|
| T1 | Reachability **passes**`check_tcp_reachable('pg-cluster.common01.svc.cluster.local', 5432)` returned `passed: True`. The env-var half of the check does not hold; see below |
| T4 | **Passes.** `tightly_coupled_local_job` reached `RUN_SUCCESS` with `contributing_hosts: ['distexec-tc-probe-hbdfl']` — one entry — and four distinct PIDs in `contributing_workers`. Separate processes, same machine, exactly as the row predicts |
`tightly_coupled_in_process_job` also succeeded, reporting a single worker.
### T1's env-var check and platform contract
The run emitted:
> Orchestration runtime env vars not visible to this process:
> `DAGSTER_POSTGRES_HOST`, `DAGSTER_POSTGRES_USER`, `DAGSTER_POSTGRES_DB`.
> Expected for a loosely coupled target; a misconfiguration for a tightly coupled one.
That warning was a false positive on a **correctly configured** platform run
pod. The chart does not set those variables: it injects `DAGSTER_PG_PASSWORD`
from `dagster-postgresql-secret` and stores host, user and database in
`dagster.yaml`. The reference check now tests for `DAGSTER_PG_PASSWORD` and
reports only its name, never its value. Database reachability is evidenced by
successful step startup: a tightly coupled step must load its run state from
the configured Dagster instance before `report_execution_target` can execute.
### T6 and T7, executed 2026-08-31
Running them needed three things the earlier attempt lacked: dagster pinned to
1.12.8 to match the control plane, so writing to the live `dataprovider01_dagster`
could not trigger a migration; step outputs moved onto the RWX
`dagster-shared-pvc`, because the default I/O manager writes them under
`$DAGSTER_HOME/storage` and each step pod otherwise gets its own empty volume;
and `automount_service_account_token: true` in `step_k8s_config`, because
`dagster-svc-account` disables it by default. The probe is
`yaml/sandbox/probe-k8s-executor-sandbox.yaml`; the run is
`d05c736a-8ec7-4e59-8cb0-9cb238db40dc`.
| # | Result |
|---|---|
| T6 | **Passes.** Six Jobs labelled `dagster/job=tightly_coupled_k8s_job` were created, one per step, each in its own pod |
| T7 | **Passes.** No step hung in `STARTING` and no step reported a connection timeout to port 5432. Every step pod opened the platform Postgres itself — the outputs and inputs below were all recorded through it |
Four steps executed and succeeded: `generate_work_units` (four dynamic outputs),
`report_execution_target`, and `process_work_unit[unit_0]` and `[unit_1]`, each
loading its input from the shared volume that a different pod wrote.
**The run then failed, and `summarise_results` never started.** The cause is a
property of the probe, not of the code or the platform:
> `Detected run worker status UNKNOWN: DagsterK8sUnrecoverableAPIError … jobs.batch`
> `"dagster-run-d05c736a-…" is forbidden: User "system:serviceaccount:dataprovider01:`
> `dagster-svc-account" cannot get resource "jobs/status" … in the namespace "dagster"`
Run monitoring polls for a run worker Job named `dagster-run-<run-id>`. The probe
starts the run with `dagster job execute` from a hand-rolled Job, so no such
object exists; and with no launcher-supplied container context the monitor looked
in the launcher's default namespace, `dagster`, where `dagster-svc-account` holds
no rights. The 403 turned *absent* into *unknown*, and the monitor failed the run
at its first poll. `process_work_unit[unit_2]` and `[unit_3]` had their pods
started already; both logged `Skipping step execution … since the run is in status
DagsterRunStatus.FAILURE` and exited 0 — which is why all six Jobs read `Complete`
while only four steps ran.
A run submitted the normal way, through the webserver to `K8sRunLauncher`, gets a
`dagster-run-<run-id>` Job in `dataprovider01` and is not exposed to this. Closing
T6/T7 end to end, including `summarise_results`, needs the code location
registered on the platform Dagster.
### T6 and T7 closed end to end, 2026-09-01
With the code location registered on the platform Dagster,
`tightly_coupled_k8s_job` was launched from the webserver and reached
`RUN_SUCCESS` as run `1d8cb167-9fb8-4a34-a036-789eac381e13`. `K8sRunLauncher`
created `dagster-run-1d8cb167-…` in `dataprovider01`, `K8sStepHandler` created one
`dagster-step-…` Job per step, and every step — including `summarise_results`
completed. No hand-rolled probe, no run-monitoring 403.
**The last thing in the way was where step outputs are written.** Two earlier
attempts failed on
`FileNotFoundError: /tmp/dagster/storage/<run-id>/generate_work_units/result/unit_0`,
with every step pod using its own container filesystem. Mounting
`dagster-shared-pvc` into the step pods was necessary but not sufficient: setting
`DAGSTER_HOME` through `step_k8s_config` does not take effect, because the Dagster
chart already injects `DAGSTER_HOME=/tmp/dagster` and the appended second entry
does not displace the first. The fix is to bypass `DAGSTER_HOME` and pin the I/O
manager instead — `fs_io_manager.configured({"base_dir": SHARED_IO_BASE_DIR})` on
the job, with `SHARED_IO_BASE_DIR` under the mounted PVC. The successful run logs
confirm it:
> Handled output "result" using IO manager "io_manager" —
> `/dagster/shared/distributed-execution/storage/1d8cb167-…/generate_work_units/result/unit_0`
The platform run exposed the false-positive `DAGSTER_POSTGRES_*` warning
described under T1 above. The reference now checks the chart's actual
`DAGSTER_PG_PASSWORD` injection instead.
> Note: `report_execution_target` reported `namespace: <not-in-kubernetes>` on a
> step pod that plainly was in Kubernetes. The check reads the service account
> namespace file, which is absent when the token is not automounted. It is a
> property of the probe, not of the run.
**C6 passes, contrary to what `job_namespace` alone suggests.** The launcher's
`job_namespace: dagster` is only a default. Each code location ships a
`DAGSTER_CONTAINER_CONTEXT` environment variable — generated by the chart — whose
`k8s.namespace` is `dataprovider01`, and the code location's context is merged
*over* the launcher's, so it wins (`dagster_k8s/container_context.py`: `namespace
= other.namespace if other.namespace else self.namespace`). Run pods therefore
land in `dataprovider01`, where `dagster-instance`, `dagster-postgresql-secret`
and `dagster-shared-pvc` all exist.
Both deployed code locations carry it, so both would launch correctly:
| Code location | `DAGSTER_CONTAINER_CONTEXT` `k8s.namespace` |
|---|---|
| `template-code-location` | `dataprovider01` |
| `semaphore-ui` | `dataprovider01` |
The successful run confirms that the code-location container context places run
and step pods in `dataprovider01` with the required namespace-local dependencies.
The residual risk is narrower than a broken namespace, but real: a code location
that reaches the launcher *without* a container context namespace inherits
`dagster` and would fail on three missing objects. The chart always sets it, so
this bites only hand-rolled pods — the reason the C6 row asks you to check the
launcher's namespace-local dependencies rather than just the namespace.
> An earlier revision of this section claimed C6 failed and that this explained
> the absence of runs. That was wrong: it read `job_namespace` without accounting
> for the container-context override.
## 3. Loosely coupled checks ## 3. Loosely coupled checks
| # | Check | How to verify | Expected evidence | | # | Check | How to verify | Expected evidence |
@@ -46,7 +197,7 @@ location image.
| L1 | Payload contract is intact | `uv run pytest tests/test_loosely_coupled.py` | `test_payload_does_not_import_dagster` passes — the payload imports `dagster_pipes` only | | L1 | Payload contract is intact | `uv run pytest tests/test_loosely_coupled.py` | `test_payload_does_not_import_dagster` passes — the payload imports `dagster_pipes` only |
| L2 | Pipes round trip works | Launch `loosely_coupled_subprocess_job` | Run reaches `SUCCESS`; run logs contain the payload's `External payload started on …` line, proving `pipes.log` crossed the channel | | L2 | Pipes round trip works | Launch `loosely_coupled_subprocess_job` | Run reaches `SUCCESS`; run logs contain the payload's `External payload started on …` line, proving `pipes.log` crossed the channel |
| L3 | Silence is treated as failure | Same test module | `test_silent_message_path_is_treated_as_failure` passes — an empty message list raises rather than yielding an empty result | | L3 | Silence is treated as failure | Same test module | `test_silent_message_path_is_treated_as_failure` passes — an empty message list raises rather than yielding an empty result |
| L4 | Payload image is pullable by the target cluster | `kubectl -n <payload-ns> run pull-probe --image=<payload-image> --restart=Never --command -- true` | Pod reaches `Completed`; no `ImagePullBackOff` | | L4 | Payload image is pullable by the target cluster | `kubectl -n <payload-ns> run pull-probe --image=<payload-image> --restart=Never --command -- true` | Pod reaches `Completed`; no `ImagePullBackOff`. Both Gitea images pull anonymously — a bare registry `GET` returns 401, but that is the start of the Docker token handshake, not a refusal |
| L5 | Dispatcher can create Jobs in the payload namespace | `kubectl -n <payload-ns> auth can-i create jobs --as=system:serviceaccount:dagster:dagster-dev` | Returns `yes` | | L5 | Dispatcher can create Jobs in the payload namespace | `kubectl -n <payload-ns> auth can-i create jobs --as=system:serviceaccount:dagster:dagster-dev` | Returns `yes` |
| L6 | Dispatcher can read pod logs — **the message channel** | `kubectl -n <payload-ns> auth can-i get pods/log --as=system:serviceaccount:dagster:dagster-dev` | Returns `yes`. A `no` here breaks reporting *without* failing the workload | | L6 | Dispatcher can read pod logs — **the message channel** | `kubectl -n <payload-ns> auth can-i get pods/log --as=system:serviceaccount:dagster:dagster-dev` | Returns `yes`. A `no` here breaks reporting *without* failing the workload |
| L7 | Payload Job is actually created | Launch `loosely_coupled_k8s_job`, then `kubectl -n <payload-ns> get jobs -l app.kubernetes.io/name=distributed-execution-payload` | One Job per dispatch, labelled `dagster/execution-target=loosely-coupled` | | L7 | Payload Job is actually created | Launch `loosely_coupled_k8s_job`, then `kubectl -n <payload-ns> get jobs -l app.kubernetes.io/name=distributed-execution-payload` | One Job per dispatch, labelled `dagster/execution-target=loosely-coupled` |
@@ -58,6 +209,26 @@ location image.
Checks L4L9 require a cluster. L1L3, L10 and L11 run on a laptop and should Checks L4L9 require a cluster. L1L3, L10 and L11 run on a laptop and should
gate every change to the payload or the dispatching op. gate every change to the payload or the dispatching op.
`yaml/loosely-coupled/probe-pipes-k8s.yaml` clears L4L9 in a single run from a
throwaway namespace, without deploying a code location or a Dagster control
plane. Prefer it over assembling the cluster checks by hand: the RBAC it grants
is exactly the set L5 and L6 ask about, so a failure localises immediately.
**L4L10 were cleared on sandbox-cat-dat on 2026-08-31** using the sandbox
variant `yaml/sandbox/probe-pipes-k8s-sandbox.yaml`. Run
`cff9b348-bfc3-4ac1-ab51-a94892b8e3a0` reached `RUN_SUCCESS` in `dataprovider01`:
four payload Jobs, four distinct payload pod hostnames in `contributing_hosts`,
and the payload's `External payload started on …` lines in the dispatcher's log,
which is the pod log stream doing its job as the message channel. No credentials
were needed anywhere.
One trap the run exposed. The platform's `dagster-svc-account` sets
`automountServiceAccountToken: false`, and the Dagster chart overrides it to
`true` on every pod it manages. A hand-written pod that does not is a plausible
future failure: the pipes client selects in-cluster authentication correctly and
then fails on `Service token file does not exist`, which points at Kubernetes
rather than at the omission.
--- ---
## 4. Common misconfiguration symptoms ## 4. Common misconfiguration symptoms
@@ -79,6 +250,7 @@ gate every change to the payload or the dispatching op.
| `env_vars_missing` is non-empty in `report_execution_target` metadata | Env vars are set on the code location deployment but not on the run pod | Add them under `runLauncher.config.k8sRunLauncher.runK8sConfig.containerConfig.env` — code location env is **not** inherited by run pods | | `env_vars_missing` is non-empty in `report_execution_target` metadata | Env vars are set on the code location deployment but not on the run pod | Add them under `runLauncher.config.k8sRunLauncher.runK8sConfig.containerConfig.env` — code location env is **not** inherited by run pods |
| A literal `vault:...` string appears as a value at runtime | Vault mutating webhook did not process the pod | Verify the `vault.security.banzaicloud.io/*` annotations are on the **run pod** template, not only the code location pod | | A literal `vault:...` string appears as a value at runtime | Vault mutating webhook did not process the pod | Verify the `vault.security.banzaicloud.io/*` annotations are on the **run pod** template, not only the code location pod |
| Steps hang in `STARTING` with `k8s_job_executor` | Service account lacks Job create/watch permission | Apply `yaml/tightly-coupled/rbac-step-executor.yaml` and confirm with `kubectl auth can-i` | | Steps hang in `STARTING` with `k8s_job_executor` | Service account lacks Job create/watch permission | Apply `yaml/tightly-coupled/rbac-step-executor.yaml` and confirm with `kubectl auth can-i` |
| `FileNotFoundError` loading a step input from `/tmp/dagster/storage/...` | Step pods each use their own container filesystem for I/O manager output | Mount an RWX volume into step pods via `step_k8s_config` **and** pin `fs_io_manager`'s `base_dir` under it. Setting `DAGSTER_HOME` in `step_k8s_config` does not work — the chart's `DAGSTER_HOME=/tmp/dagster` is injected first and wins |
| `contributing_hosts` shows one host when `k8s_job_executor` is configured | Run tags or Launchpad config overrode the executor, or the image predates the change | Confirm the code location reloaded after the image bump; check the run's *Config* tab for an `execution:` override | | `contributing_hosts` shows one host when `k8s_job_executor` is configured | Run tags or Launchpad config overrode the executor, or the image predates the change | Confirm the code location reloaded after the image bump; check the run's *Config* tab for an `execution:` override |
| Step pods `OOMKilled` under fan-out | Per-step memory limit applied per pod, aggregate exceeded quota | Raise `step_k8s_config` limits or lower step concurrency; the two multiply | | Step pods `OOMKilled` under fan-out | Per-step memory limit applied per pod, aggregate exceeded quota | Raise `step_k8s_config` limits or lower step concurrency; the two multiply |
| Postgres refuses connections once fan-out grows | Each step pod is an independent DB client | Reduce step concurrency, raise the Postgres connection limit, or move the fan-out step to a loosely coupled target | | Postgres refuses connections once fan-out grows | Each step pod is an independent DB client | Reduce step concurrency, raise the Postgres connection limit, or move the fan-out step to a loosely coupled target |
@@ -96,9 +268,17 @@ gate every change to the payload or the dispatching op.
| Payload receives no `units` | `extras` key mismatch between dispatcher and `pipes.get_extra()` | Both sides must use the same key; a typo yields a `KeyError` inside the payload | | Payload receives no `units` | `extras` key mismatch between dispatcher and `pipes.get_extra()` | Both sides must use the same key; a typo yields a `KeyError` inside the payload |
| Run cancelled in the UI, payload pod keeps running | Cancellation is not propagated to dispatched workloads automatically | `delete_pod_on_completion` handles the normal path; for cancellation, verify orphaned Jobs and add a cleanup sensor | | Run cancelled in the UI, payload pod keeps running | Cancellation is not propagated to dispatched workloads automatically | `delete_pod_on_completion` handles the normal path; for cancellation, verify orphaned Jobs and add a cleanup sensor |
> **NOT CLUSTER-VERIFIED.** Rows referencing Kubernetes behaviour follow from the > **Partly observed.** The pipes rows were exercised on sandbox-cat-dat on
> implemented reference and the dagster-k8s API, but have not been observed on a > 2026-08-31. The tightly coupled `k8s_job_executor` rows were closed on
> Simpl cluster. Confirm and amend after the first cluster run. > 2026-09-01 by run `1d8cb167-9fb8-4a34-a036-789eac381e13`; the remaining rows in
> the table above still follow from the dagster-k8s API rather than from
> observation.
>
> One symptom the cluster run added, absent from the table above: a service
> account with `automountServiceAccountToken: false` — which the platform's
> `dagster-svc-account` uses — makes the pipes client fail with
> `ConfigException: Service token file does not exist`. It reads as a Kubernetes
> fault; the fix is `automountServiceAccountToken: true` on the pod.
--- ---

View File

@@ -1 +1 @@
PROJECT_VERSION_NUMBER="0.1.0" PROJECT_VERSION_NUMBER="0.0.1"

View File

@@ -3,11 +3,16 @@ name = "distributed_execution"
version = "0.1.0" version = "0.1.0"
description = "Reference implementations and user guide for Dagster distributed execution targets and integration patterns" description = "Reference implementations and user guide for Dagster distributed execution targets and integration patterns"
requires-python = ">=3.12" requires-python = ">=3.12"
# Pinned to the exact control plane version, not just the 1.12 line. A code
# location is a gRPC server the webserver and daemon call into, and step pods
# share a metadata database schema with them. Patch releases can carry schema
# migrations, so "close enough" is not a safe position against a shared database.
# Revisit when the platform upgrades; the libraries track dagster as 0.28.x.
dependencies = [ dependencies = [
"dagster", "dagster==1.12.8",
"dagster-k8s>=0.27.16", "dagster-k8s==0.28.8",
"dagster-postgres>=0.27.16", "dagster-postgres==0.28.8",
"dagster-webserver>=1.11.16", "dagster-webserver==1.12.8",
"pip>=26.1.2", "pip>=26.1.2",
"pydantic>=2.0", "pydantic>=2.0",
] ]

View File

@@ -1,6 +1,6 @@
dagster dagster==1.12.8
dagster-k8s>=0.27.16 dagster-k8s==0.28.8
dagster-postgres>=0.27.16 dagster-postgres==0.28.8
dagster-webserver>=1.11.16 dagster-webserver==1.12.8
pip>=26.1.2 pip>=26.1.2
pydantic>=2.0 pydantic>=2.0

View File

@@ -38,7 +38,8 @@ PAYLOAD_SCRIPT = os.environ.get("PIPES_PAYLOAD_SCRIPT", str(_REPO_ROOT / "payloa
PAYLOAD_IMAGE = os.environ.get( PAYLOAD_IMAGE = os.environ.get(
"PIPES_PAYLOAD_IMAGE", "PIPES_PAYLOAD_IMAGE",
"code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/payload:0.1.0", "code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services"
"/distributed-execution/distributed-execution/payload:0.0.1",
) )
PAYLOAD_NAMESPACE = os.environ.get("PIPES_PAYLOAD_NAMESPACE", "dagster") PAYLOAD_NAMESPACE = os.environ.get("PIPES_PAYLOAD_NAMESPACE", "dagster")

View File

@@ -12,9 +12,7 @@ from urllib.parse import urlparse
# Runtime dependencies a tightly coupled execution pod must be able to resolve. # Runtime dependencies a tightly coupled execution pod must be able to resolve.
TIGHTLY_COUPLED_ENV_VARS = ( TIGHTLY_COUPLED_ENV_VARS = (
"DAGSTER_POSTGRES_HOST", "DAGSTER_PG_PASSWORD",
"DAGSTER_POSTGRES_USER",
"DAGSTER_POSTGRES_DB",
) )

View File

@@ -12,7 +12,7 @@ is the instance-level run launcher (see ``yaml/tightly-coupled/``).
from __future__ import annotations from __future__ import annotations
from dagster import graph, in_process_executor, multiprocess_executor from dagster import fs_io_manager, graph, in_process_executor, multiprocess_executor
from dagster_k8s import k8s_job_executor from dagster_k8s import k8s_job_executor
from distributed_execution.ops import ( from distributed_execution.ops import (
@@ -28,6 +28,11 @@ COMMON_TAGS = {
"business_operation": "DISTRIBUTED_EXECUTION_REFERENCE", "business_operation": "DISTRIBUTED_EXECUTION_REFERENCE",
} }
# RWX PVC mounted into the run worker and every step pod. Set as the I/O manager
# base_dir rather than via DAGSTER_HOME: the Dagster chart already injects
# DAGSTER_HOME=/tmp/dagster and the earlier duplicate wins in the step pod.
SHARED_IO_BASE_DIR = "/dagster/shared/distributed-execution/storage"
# Per-step pod shape. Only honoured by k8s_job_executor. # Per-step pod shape. Only honoured by k8s_job_executor.
STEP_K8S_CONFIG = { STEP_K8S_CONFIG = {
"container_config": { "container_config": {
@@ -35,9 +40,21 @@ STEP_K8S_CONFIG = {
"requests": {"cpu": "100m", "memory": "128Mi"}, "requests": {"cpu": "100m", "memory": "128Mi"},
"limits": {"cpu": "500m", "memory": "512Mi"}, "limits": {"cpu": "500m", "memory": "512Mi"},
}, },
"volume_mounts": [
{
"name": "dagster-shared-storage",
"mount_path": "/dagster/shared",
}
],
}, },
"pod_spec_config": { "pod_spec_config": {
"restart_policy": "Never", "restart_policy": "Never",
"volumes": [
{
"name": "dagster-shared-storage",
"persistent_volume_claim": {"claim_name": "dagster-shared-pvc"},
}
],
}, },
} }
@@ -81,12 +98,21 @@ tightly_coupled_k8s_job = distributed_execution_reference.to_job(
"Tightly coupled, one Kubernetes Job per step. Each step pod must reach the metadata " "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." "database, object storage and Vault. Requires a cluster - not runnable locally."
), ),
executor_def=k8s_job_executor.configured( # Defaults go through `config` rather than `executor_def=...configured(...)`.
{ # `.configured()` collapses the executor's config schema to Any, so a run
# config `execution:` block is accepted and then silently discarded - which
# also makes job_image and job_namespace impossible to supply at launch time.
executor_def=k8s_job_executor,
# Steps run in separate pods, so step outputs have to land on shared storage.
resource_defs={"io_manager": fs_io_manager.configured({"base_dir": SHARED_IO_BASE_DIR})},
config={
"execution": {
"config": {
"image_pull_policy": "IfNotPresent", "image_pull_policy": "IfNotPresent",
"step_k8s_config": STEP_K8S_CONFIG, "step_k8s_config": STEP_K8S_CONFIG,
} }
), }
},
tags={**COMMON_TAGS, "executor": "k8s_job"}, tags={**COMMON_TAGS, "executor": "k8s_job"},
) )

View File

@@ -65,9 +65,7 @@ def test_each_unit_is_dispatched_to_its_own_external_worker():
def test_payload_reports_no_orchestration_credentials(monkeypatch): def test_payload_reports_no_orchestration_credentials(monkeypatch):
monkeypatch.delenv("DAGSTER_POSTGRES_HOST", raising=False) monkeypatch.delenv("DAGSTER_PG_PASSWORD", raising=False)
monkeypatch.delenv("DAGSTER_POSTGRES_USER", raising=False)
monkeypatch.delenv("DAGSTER_POSTGRES_DB", raising=False)
result = loosely_coupled_subprocess_job.execute_in_process() result = loosely_coupled_subprocess_job.execute_in_process()
mapped = result.output_for_node("dispatch_external_work_subprocess") mapped = result.output_for_node("dispatch_external_work_subprocess")

View File

@@ -5,6 +5,8 @@ import pytest
from distributed_execution.preflight import check_env_vars, describe_pod_identity from distributed_execution.preflight import check_env_vars, describe_pod_identity
from distributed_execution.repository import defs from distributed_execution.repository import defs
from distributed_execution.tightly_coupled.jobs import ( from distributed_execution.tightly_coupled.jobs import (
SHARED_IO_BASE_DIR,
STEP_K8S_CONFIG,
tightly_coupled_in_process_job, tightly_coupled_in_process_job,
tightly_coupled_k8s_job, tightly_coupled_k8s_job,
tightly_coupled_local_job, tightly_coupled_local_job,
@@ -35,6 +37,24 @@ def test_each_job_declares_its_execution_target(job, expected_executor):
assert job.tags["executor"] == expected_executor assert job.tags["executor"] == expected_executor
def test_k8s_step_pods_mount_shared_dagster_storage():
container_config = STEP_K8S_CONFIG["container_config"]
pod_spec_config = STEP_K8S_CONFIG["pod_spec_config"]
assert {"name": "dagster-shared-storage", "mount_path": "/dagster/shared"} in container_config["volume_mounts"]
assert {
"name": "dagster-shared-storage",
"persistent_volume_claim": {"claim_name": "dagster-shared-pvc"},
} in pod_spec_config["volumes"]
assert SHARED_IO_BASE_DIR.startswith("/dagster/shared/")
def test_k8s_job_pins_io_manager_to_shared_storage():
io_manager = tightly_coupled_k8s_job.resource_defs["io_manager"]
resolved = io_manager.apply_config_mapping({}).value
assert resolved["config"]["base_dir"] == SHARED_IO_BASE_DIR
def test_in_process_job_runs_end_to_end(): def test_in_process_job_runs_end_to_end():
result = tightly_coupled_in_process_job.execute_in_process() result = tightly_coupled_in_process_job.execute_in_process()
@@ -61,6 +81,16 @@ def test_env_var_check_reports_missing_names():
assert result["missing"] == ["DEFINITELY_NOT_SET_12345"] assert result["missing"] == ["DEFINITELY_NOT_SET_12345"]
def test_env_var_check_reports_present_names(monkeypatch):
monkeypatch.setenv("DAGSTER_PG_PASSWORD", "not-exposed-in-evidence")
result = check_env_vars(("DAGSTER_PG_PASSWORD",))
assert result["passed"] is True
assert result["present"] == ["DAGSTER_PG_PASSWORD"]
assert "not-exposed-in-evidence" not in repr(result)
def test_pod_identity_falls_back_outside_kubernetes(monkeypatch): def test_pod_identity_falls_back_outside_kubernetes(monkeypatch):
monkeypatch.delenv("DAGSTER_K8S_PIPELINE_RUN_NAMESPACE", raising=False) monkeypatch.delenv("DAGSTER_K8S_PIPELINE_RUN_NAMESPACE", raising=False)

294
uv.lock generated
View File

@@ -7,128 +7,6 @@ resolution-markers = [
"python_full_version < '3.13'", "python_full_version < '3.13'",
] ]
[[package]]
name = "aiohappyeyeballs"
version = "2.7.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ce/f4/eec0465c2f67b2664688d0240b3212d5196fd89e741df67ddb81f8d35658/aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d", size = 24757, upload-time = "2026-07-01T17:11:55.501Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472", size = 15038, upload-time = "2026-07-01T17:11:54.055Z" },
]
[[package]]
name = "aiohttp"
version = "3.14.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohappyeyeballs" },
{ name = "aiosignal" },
{ name = "attrs" },
{ name = "frozenlist" },
{ name = "multidict" },
{ name = "propcache" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
{ name = "yarl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/d4/eb96299230e20acf2efae207cb8d69051f1f68e357e5ea5e479bf6fb097a/aiohttp-3.14.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:39aded8c7f3b935b54aab1d8d73c70ec0ee2d3ec3b943e0e86611bc150ba47f5", size = 754690, upload-time = "2026-07-23T01:53:47.332Z" },
{ url = "https://files.pythonhosted.org/packages/88/11/e7a70a209eb9a067c0d3212b518a0134e3484f5178c7533878b6b514d469/aiohttp-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5bcb6ff3fdab1258a192679ff1a05d44f59626430aa05cd1a9d2447423599228", size = 509484, upload-time = "2026-07-23T01:53:51.159Z" },
{ url = "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:617105e2c3018ee38d0c8ce5ee3c84f621a6d8b9f723202aacaff28449ca91ee", size = 511949, upload-time = "2026-07-23T01:53:55.083Z" },
{ url = "https://files.pythonhosted.org/packages/54/b9/42e74c46b7b7c794b995bbc1f573fb48950c38b19d8600c62a6804ee2d67/aiohttp-3.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f631fe87a6f30df5fbe6d79640b25e4cffb38c31c7fb6f10871517b84b0f8c1a", size = 1765282, upload-time = "2026-07-23T01:53:59.662Z" },
{ url = "https://files.pythonhosted.org/packages/6b/ed/62bc4d74363ad346d518e0720363a949f63e2e23439a79eb5813d4d29bb3/aiohttp-3.14.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a94dbaae5ae27bd849c93570669bff91e0510f33a80805738e3de72a7be0447b", size = 1741511, upload-time = "2026-07-23T01:54:04.063Z" },
{ url = "https://files.pythonhosted.org/packages/d0/9f/181e8a8bc79e47d13c7fc4540bd7a3b729d9505609c61f392a8dd2fbfe55/aiohttp-3.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f2f1c4c032c7cedd7d8da6f54c97b70266c6570c3108d3fdffee7188bb70529", size = 1810680, upload-time = "2026-07-23T01:54:09.882Z" },
{ url = "https://files.pythonhosted.org/packages/5c/9a/dec94d6ad694552fe3424e3f1928d7a606a5d9d9433a04e7ecdd9d38ae7f/aiohttp-3.14.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea05e1f97ceea523942d9b2a7d7c0359d781d683d6b043f5943a602b14da4787", size = 1905646, upload-time = "2026-07-23T01:54:13.475Z" },
{ url = "https://files.pythonhosted.org/packages/52/b7/7cd31f29d6055bd711ae6e669367fba6f5ae9de463910a793e30556a8db7/aiohttp-3.14.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:543906c127fb1d929b95076db19b83fa2d46751006ff1e23b093aa5ac4d8db42", size = 1792122, upload-time = "2026-07-23T01:54:15.752Z" },
{ url = "https://files.pythonhosted.org/packages/66/73/10b1ef93afa61f4963c746257b70ced619cf31a4798671de5fdb2608501d/aiohttp-3.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0a5ff2dfbb9ce645fa5b8ef3e02c6c0b9cc3f6030ff863d0c51fffc50cb5541b", size = 1591127, upload-time = "2026-07-23T01:54:19.489Z" },
{ url = "https://files.pythonhosted.org/packages/49/ed/3b203fa6de1b338c14acdc06bf6ca9b043b7944f005966958c2ced932cde/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:041badb8f84396357c4d3ad26de6afd7a32b112f43d3c63045c0c8278cfd2043", size = 1725210, upload-time = "2026-07-23T01:54:24.129Z" },
{ url = "https://files.pythonhosted.org/packages/28/b7/1c2aab8c706436dcc28598452488ac9cd7c409da815237c28c27d58993e6/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:530125ee1163c4219af35dc3aa1206e541e7b31b6efc1a3f93b70a136f65d427", size = 1764848, upload-time = "2026-07-23T01:54:27.973Z" },
{ url = "https://files.pythonhosted.org/packages/54/50/94c28f08b131c4bf10984ea2c7a536c9920608bb2d6e7f95642c30cc87b7/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8653fd547c93a61aadc612007790f5555cdd18946fa48cf45e26d8ea4ea473d", size = 1777102, upload-time = "2026-07-23T01:54:31.775Z" },
{ url = "https://files.pythonhosted.org/packages/13/d4/e7d09ba7d345fb2d74440fd2fa033c5e079fac05552927705986f41a364f/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:89176250f686cb9853c0fb7ead90e639e915b84a6f43eedc2a4e7ec21f1037f0", size = 1580205, upload-time = "2026-07-23T01:54:34.518Z" },
{ url = "https://files.pythonhosted.org/packages/a3/84/072a91d68e1e1eb587985b54baab94221277f877e8ef274fc213a0ceae28/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3a26434dafe408229ff3403458ca58de24fb51936504decac49ce6755f77e59d", size = 1797219, upload-time = "2026-07-23T01:54:36.995Z" },
{ url = "https://files.pythonhosted.org/packages/e0/eb/aad34e897e668424d6e995da5dff8a4a09af93363d3392488772957a63aa/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d1558173930a5a8d3069cee5c92fc91c87c4dbcb099debbb3622053717145a19", size = 1768629, upload-time = "2026-07-23T01:54:40.103Z" },
{ url = "https://files.pythonhosted.org/packages/b6/2b/6bb88ddba0fecd9122aa3ebcad25996cf6c083a4a7040dbb3a4f97972af6/aiohttp-3.14.3-cp312-cp312-win32.whl", hash = "sha256:16100ad3ab8d649fdfbee87602d9d2dcdca9df0b9eda8a1b5fdc0d41f96da559", size = 451481, upload-time = "2026-07-23T01:54:42.547Z" },
{ url = "https://files.pythonhosted.org/packages/76/9b/f2f8f108da17ecef2cc3efc424e8b7ad3782b1a8360f7b8eae8ced84f6ea/aiohttp-3.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:33a2d7c28d33797a2e99923dffa63f83d908a19b6bf26cfe80fa790aa5e1a75a", size = 476845, upload-time = "2026-07-23T01:54:44.853Z" },
{ url = "https://files.pythonhosted.org/packages/3e/44/28dac80a8941b604f4da10ce21097614ca1bf905ce93dca28d8d7de9c1e7/aiohttp-3.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:362a3fd481769cac1a824514bcd86fda51c65e8fe6e051099e008fddde6db17c", size = 448050, upload-time = "2026-07-23T01:54:47.087Z" },
{ url = "https://files.pythonhosted.org/packages/57/be/5afd201cc0ab139029aadb75392efe85a293403d9dd3a3226161c21ce00c/aiohttp-3.14.3-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:2e9878ae68e4a5f1c0abe4dd497dbc3d51946f5837b56759e2a02e78fa90ef86", size = 506269, upload-time = "2026-07-23T01:54:49.075Z" },
{ url = "https://files.pythonhosted.org/packages/22/09/dec8189d62b45ade009f6792a2264b942a90cb88aeaf181239933cd72c3c/aiohttp-3.14.3-cp313-cp313-android_21_x86_64.whl", hash = "sha256:f3d2669fe7dec7fc359ecdb5984b29b50d85d5d00f8c1cb61de4f4a24ee42627", size = 515166, upload-time = "2026-07-23T01:54:51.894Z" },
{ url = "https://files.pythonhosted.org/packages/28/24/2854869d29ed8a8b19d74f9ec6629515f7e04d02dd329d9d179201e58e47/aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:cc7cb243a68167172f48c1fd43cee91ec4b1d40cefd190edd43369d1a6bc9c82", size = 486263, upload-time = "2026-07-23T01:54:54.223Z" },
{ url = "https://files.pythonhosted.org/packages/d4/dd/57187c8be2a35aea65eaee3bd2c3dcbbcf0204f5106c89637e3610380cd1/aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:78253b573e6ffab5028924fc98bc281aae05445969982a10864bc360dea2016c", size = 492299, upload-time = "2026-07-23T01:54:56.236Z" },
{ url = "https://files.pythonhosted.org/packages/b9/11/06ae6ed8f0d414edf4068861e233d8fe23ee699bfd4b3ceb8663db948a62/aiohttp-3.14.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7041d52c3a7fa20c9e8c182b534704abb19502c8bdcbde7ab23bfda6f642394f", size = 502235, upload-time = "2026-07-23T01:54:58.377Z" },
{ url = "https://files.pythonhosted.org/packages/7e/a3/559639c34a345d2cf7c52dff6838119f2eaf29eb508227b5b83f573af813/aiohttp-3.14.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac74facc01463f138b0da5580329cfcc82818dea5656e83ddcd11268fc12ff80", size = 750883, upload-time = "2026-07-23T01:55:00.65Z" },
{ url = "https://files.pythonhosted.org/packages/91/cd/41e131f13afd1e7b0172a9d9eda085ef90eb8439f41f0d279db81ed3ae60/aiohttp-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d6218d92e450824e9b4881f44e8c09f1853b490f9a64130801024a4793b1b3b0", size = 508473, upload-time = "2026-07-23T01:55:02.945Z" },
{ url = "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:11fb37ef075669eee52ab1928fbf6e1741fada40409fa309ebde9607a962aebf", size = 509190, upload-time = "2026-07-23T01:55:05.173Z" },
{ url = "https://files.pythonhosted.org/packages/97/21/6464573e53d69672cc1eada3e5c5cb2d2efa82701e8305a0f2047a576967/aiohttp-3.14.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55bdcc472aafe2de4a253045cc128007a64f1e0264fb675791e132ea5edaa3bd", size = 1761478, upload-time = "2026-07-23T01:55:07.383Z" },
{ url = "https://files.pythonhosted.org/packages/1a/81/d217043a4c17fbce360905e3b2bdd20139ebc9a2de836d035d179c4da006/aiohttp-3.14.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c39846c3aad97a8530c89d7a3869a8f8e9e3762c6ac0504481e5c80948f7e807", size = 1735092, upload-time = "2026-07-23T01:55:09.803Z" },
{ url = "https://files.pythonhosted.org/packages/a1/66/e13a02d0eeb1a9a502402a977abb4e4abff9fe4051c26f80558c57a7c975/aiohttp-3.14.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5895ef58c4620afe02fa16044f023dc4dafec08158f9d08874a46a7dbc0341b8", size = 1800546, upload-time = "2026-07-23T01:55:12.012Z" },
{ url = "https://files.pythonhosted.org/packages/26/5e/57d42fca1d18cb5acc1cad945d017fabc5d6ae71d8a08ad66be8dc3ee544/aiohttp-3.14.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa9467a8113aa69d3d7c55a70ef0b7c636010a40993f3df9d9d0d73b3eb7ef24", size = 1895250, upload-time = "2026-07-23T01:55:14.357Z" },
{ url = "https://files.pythonhosted.org/packages/ca/1c/7da8d08e74d56f00070822f9638ff3f1c563f8ad87d1efa996c87bfc8644/aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7d2deec16eeedf55f2c7cf75b521ea3856a5177e123844f8fd0f114ce252cb5", size = 1789289, upload-time = "2026-07-23T01:55:16.668Z" },
{ url = "https://files.pythonhosted.org/packages/cd/0f/cf16bcf56896981c1a0319f5d5db9337994b5165730c48a8fa07e9b34be6/aiohttp-3.14.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dd54d0e8717de95939766febac482ac0474d8ac3b048115f9f2b1d23a16e7db4", size = 1586706, upload-time = "2026-07-23T01:55:18.913Z" },
{ url = "https://files.pythonhosted.org/packages/fe/6f/76eac12a7f2480e1e304f842efdb07db33256b0d9165b866b6ef0806c202/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:df82f3787c940c94986b34222d59c9e38843fba85139f36e85255a82ad5355a9", size = 1724652, upload-time = "2026-07-23T01:55:21.296Z" },
{ url = "https://files.pythonhosted.org/packages/39/b6/19c8c592baeeb94b75f966547d40c02ac7590902306ec5863d5c027cf506/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:42a67efc36300d052fb4508a53e8b6901b9284b599ae63945c377569c5fcc1e1", size = 1756239, upload-time = "2026-07-23T01:55:23.705Z" },
{ url = "https://files.pythonhosted.org/packages/dc/c9/4e9383150296f97f873b680c4de8fb2cd88608fb9f48c79edcb111611abc/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7a75aa63cbf9b21cfaf60dc2657e19df2c2867d91707d653fee171ffeedd1371", size = 1769161, upload-time = "2026-07-23T01:55:26.082Z" },
{ url = "https://files.pythonhosted.org/packages/aa/1e/147bdc6cc5de5f3ab011be8bf5d6e786633249f22c20bae06f85e45f5387/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e92eb8acc45eb6a9f4935071a77edf5b85cc6f8dfad5cd99e97653c26593cdde", size = 1578759, upload-time = "2026-07-23T01:55:28.846Z" },
{ url = "https://files.pythonhosted.org/packages/fd/31/78388a9d6040ece2e11df62ea229a822cf5e52d238374b220ae9975b2623/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b014a6ed7cf912e787149fdc529166d3ceabac23f26efeea3158c9aba2354e7e", size = 1792025, upload-time = "2026-07-23T01:55:31.457Z" },
{ url = "https://files.pythonhosted.org/packages/03/51/a3d29fdf2c25d796746af8ad6fe56a45d6256c38b0a8a2ed752e1160b3a2/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3d4f72af88ac2474bb5bca640030320e3d38a0163a1d7533500e87be458eef71", size = 1768477, upload-time = "2026-07-23T01:55:33.87Z" },
{ url = "https://files.pythonhosted.org/packages/29/a6/442e18b5afeade534d877a2dc3c3e392aff8d49787890b0cf84790410267/aiohttp-3.14.3-cp313-cp313-win32.whl", hash = "sha256:5f08ec777f35ee70720233b8b9811d3bb5d728137f30ac91b7457709c3261ac0", size = 451069, upload-time = "2026-07-23T01:55:36.121Z" },
{ url = "https://files.pythonhosted.org/packages/9d/69/3d876ac02659f271cf7f6769f14a8e3de5b6e888ed8b5a7e998086a4cec8/aiohttp-3.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:dff9461ec275f22135650d5ba4b4931a11f3958df7dfbb8db630000d4dee0883", size = 476518, upload-time = "2026-07-23T01:55:38.303Z" },
{ url = "https://files.pythonhosted.org/packages/b2/0e/50d6e6471cd31edce8b282bdec59375a3a69124d8a989a0b1313355cae52/aiohttp-3.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:ddcac3c6b382e81f1dd0499199d4136b877beb4cb5ef770bbbfba56c4b8f55d2", size = 447676, upload-time = "2026-07-23T01:55:40.451Z" },
{ url = "https://files.pythonhosted.org/packages/c8/20/887fdcf832326571b370ffc347b3e70abe101096f3720126aac161b1d872/aiohttp-3.14.3-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:49f7325beb0f85ef4aef5f48f490269575f83e6e2acad00a1d80b807eb027062", size = 509067, upload-time = "2026-07-23T01:55:42.618Z" },
{ url = "https://files.pythonhosted.org/packages/ad/a3/92cec936f78cc4bf0fa5554ebe593b73459d94e3c62303e1902a4cccb6f7/aiohttp-3.14.3-cp314-cp314-android_24_x86_64.whl", hash = "sha256:e3be98a7c30b8c25d573dafba7171d66dfb05ee6a9070fc46535464ff97700a6", size = 514774, upload-time = "2026-07-23T01:55:44.937Z" },
{ url = "https://files.pythonhosted.org/packages/29/ba/2a0c38df3fc557620b6a5acd98364af050053b6285b4dc7ee74100c63c18/aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:614c61d478b83953e261d02bb2df750f17227cd33ef8002945bf5aebbde21919", size = 488134, upload-time = "2026-07-23T01:55:47.135Z" },
{ url = "https://files.pythonhosted.org/packages/48/d6/d51b7d4bf309af3693940d8ffd2b9ed0b682434ef85959b7c9c137f60cf8/aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:1caa7b0d05f3e3a36f87788c59e970a7ee1cefcfcbb924a9f138c4a6551c9cb7", size = 494201, upload-time = "2026-07-23T01:55:49.451Z" },
{ url = "https://files.pythonhosted.org/packages/3f/5a/8f624384e5f1efabb5229b94157eb966b021e97bdb188c62860c2ae243c2/aiohttp-3.14.3-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:dfa68deb2a443bdaa3ea5297b0699c1464f08aef3812b486d1348eee61b07dc0", size = 502766, upload-time = "2026-07-23T01:55:51.656Z" },
{ url = "https://files.pythonhosted.org/packages/a6/26/4ff0164370deec18fb19254ee4ab10b7a73304ac0c860b13f5f84663759b/aiohttp-3.14.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:e72ee89e28d907a18f46959b4eb0bb06701cc7f8cf4366e00029e2ccfaaf5924", size = 756557, upload-time = "2026-07-23T01:55:53.964Z" },
{ url = "https://files.pythonhosted.org/packages/97/a3/7056b86dc0d9ec709ea9777eae3b0161428f943372f8b98c01c11593b682/aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ad4c8b7488d745d2ca4838ebd8ae5ba9b56341d30b1da43640e4ce87f9f49646", size = 510168, upload-time = "2026-07-23T01:55:56.22Z" },
{ url = "https://files.pythonhosted.org/packages/85/ed/0357a015892fd68058bf2d39d3fd1958e459b997a7db30aaa6aaa434ae96/aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:db332af25642007330fca8be5c4d194caf2bea7a7fc84415aff3497af5dfee6b", size = 512957, upload-time = "2026-07-23T01:55:58.437Z" },
{ url = "https://files.pythonhosted.org/packages/47/d1/8aba53f15ccb2238405f5e9d30e2a8ca44f93878c26e7165ade00d374b1c/aiohttp-3.14.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25bd2708db6bdf6a6630dd37bdcdfcb47c4434d22ac69c64665b802910140b30", size = 1750149, upload-time = "2026-07-23T01:56:00.856Z" },
{ url = "https://files.pythonhosted.org/packages/49/bd/40c3fee327529284375c6701cbb0fa4600cc2e8432af1378f897e2ef7d3a/aiohttp-3.14.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cef89a58e628c4efcac3275c2d68083f82426dcdc89c1492a6f654f9f7ea6ab9", size = 1707685, upload-time = "2026-07-23T01:56:03.371Z" },
{ url = "https://files.pythonhosted.org/packages/2a/a3/ca0cc6724cca8114b05694abd916060758c79894c3aa5b012cdadc1bc28e/aiohttp-3.14.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c23ec8ee9d5ab2f5421f9c7fffce208435607af27fd46d4a44e031954352838f", size = 1803911, upload-time = "2026-07-23T01:56:05.817Z" },
{ url = "https://files.pythonhosted.org/packages/95/b5/85b099c299c3ffd38ad9b3e43694c8a346934e4a30c88c4fd5a841234f77/aiohttp-3.14.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e2667f0bbe7eb6c74eae5e9691441ad186e5845ca3cff63230fc09c4e7514f5d", size = 1876929, upload-time = "2026-07-23T01:56:08.413Z" },
{ url = "https://files.pythonhosted.org/packages/d5/b7/1da684a04175473fa4cddbf9a2f572e79514c3fd27a74597f43057d4f3da/aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18cb43369747b2ae007bd2655fb8e63a099c2ff1d207962943636dac989b3147", size = 1761112, upload-time = "2026-07-23T01:56:10.918Z" },
{ url = "https://files.pythonhosted.org/packages/d1/16/bc4b55e3e5cb175fd69c53c90d60d2f47797cb343da5106e23863dc4dba4/aiohttp-3.14.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d77640cc618c1d99fc4f8589c0f24a730adfa54eb1e57ef7bf0c8dfb78da898c", size = 1583500, upload-time = "2026-07-23T01:56:13.613Z" },
{ url = "https://files.pythonhosted.org/packages/2a/e8/13a9d957a1ee40837f46aa30f0f4c657e673ad86a2e6362a9f9be20d26d9/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:53e5179d8abb5710f8e83ba207c41c8d1261fcffd4616500e15ca2b7a33be10a", size = 1713940, upload-time = "2026-07-23T01:56:15.969Z" },
{ url = "https://files.pythonhosted.org/packages/38/05/d33c680c1bcf1c7e130f9cbfc1fc02fe8bb0c4af2a94a53dd5fb56131e5c/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:cd817772b2fcf2b8c0905795318485f9ec16eae60b29feb7f4c77085311637f0", size = 1724413, upload-time = "2026-07-23T01:56:18.591Z" },
{ url = "https://files.pythonhosted.org/packages/85/1d/af798d306f7a74b6a632dbcabcf62a4c91391b7582d2a8c6d7712e2cc54e/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4e3ac92d90e92773b2362d506068e9a948192bd553e743c5b2429e28527c8661", size = 1770748, upload-time = "2026-07-23T01:56:21.074Z" },
{ url = "https://files.pythonhosted.org/packages/a8/92/ad720d472556a995049206867765e9410969684f86ee09423ff9969044c1/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3f42e9b78301f11c8f861746175d8b9c1ccef713fcad9eab396e2f6db8ed4a22", size = 1577564, upload-time = "2026-07-23T01:56:23.475Z" },
{ url = "https://files.pythonhosted.org/packages/60/ad/0ed7586cbef7a884e23a752fa2bb987a122e6a5dd50dab109258d0a95193/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9d9edccfe496b476db5f398d97b865e9a6752bcf8aec4eef8390ce20fb64bb41", size = 1782080, upload-time = "2026-07-23T01:56:25.994Z" },
{ url = "https://files.pythonhosted.org/packages/97/ea/dbaed0d73e8a69aad653b045dab451c67c2454bb731a37b45a86593e9422/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c5ec8fb1bcc31a8466f74aaf26c345d5c386fa4bd08a3f0eb9c7a4a3fe8b5bf", size = 1745813, upload-time = "2026-07-23T01:56:28.604Z" },
{ url = "https://files.pythonhosted.org/packages/81/1b/6893d4bc57e434fc93a6c9217c637d967a0b651d989f6e3265179375754a/aiohttp-3.14.3-cp314-cp314-win32.whl", hash = "sha256:38901a84da3ce22249f6e860bf8f90d141bcab7da090cc398f8bb58c0e44b7da", size = 455872, upload-time = "2026-07-23T01:56:31.031Z" },
{ url = "https://files.pythonhosted.org/packages/f5/8b/c7baa1ba1eda4db6989baefe5de6d99834921b84ebd7918624febcb9f290/aiohttp-3.14.3-cp314-cp314-win_amd64.whl", hash = "sha256:8b3b60de05f3dcb6f6a00f818bb2ec781cee4de0645f59ccaf99b1d1823b6100", size = 481030, upload-time = "2026-07-23T01:56:33.365Z" },
{ url = "https://files.pythonhosted.org/packages/22/8c/c29d067df825a2df88ca432db848aa2fe8199598359cc06c12b09320cac9/aiohttp-3.14.3-cp314-cp314-win_arm64.whl", hash = "sha256:1576145bdceeb92382d899751e12743a3a5b8e460a841e3e50543859e54864dc", size = 453669, upload-time = "2026-07-23T01:56:35.731Z" },
{ url = "https://files.pythonhosted.org/packages/6a/a4/9c033beb355d39b6147980597ec9645e4729243f686ee4dc73945de72030/aiohttp-3.14.3-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:8800c996b01c2772a783e3e46f3e1abd5823029adca0df54231960de9bfefa5b", size = 791403, upload-time = "2026-07-23T01:56:37.972Z" },
{ url = "https://files.pythonhosted.org/packages/80/ca/87c32a0a7704583cfc49660bd817889bae5b830bf53b5dcb4e92145ac2da/aiohttp-3.14.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ebe8e504f058fe91223351cecd2d9d6946c9d241bb0250d898ffbdf584cc72b0", size = 526413, upload-time = "2026-07-23T01:56:40.523Z" },
{ url = "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:30402d03a7c0ff52bce290b57e564e9079fd9d0cb545c8aba73f86a103162d2e", size = 532135, upload-time = "2026-07-23T01:56:42.876Z" },
{ url = "https://files.pythonhosted.org/packages/fe/45/f8919fd936e8b79fcd9bda7b6d8e62613462a713f4f17987fd7c34399142/aiohttp-3.14.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9fc7b5bfec6573f3ae844f457fdde5adeb713f8b8e4a81ad64fc207b49383716", size = 1922742, upload-time = "2026-07-23T01:56:45.528Z" },
{ url = "https://files.pythonhosted.org/packages/f6/ec/9ca76b28a27525b0cc53e20842e0228b022f301ce1f436b7d814b4aaf2df/aiohttp-3.14.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8a5fd34f7f7410d1730d5c2ba873cacb2eed3fede366feb268a70ba22581ed8f", size = 1787371, upload-time = "2026-07-23T01:56:48.045Z" },
{ url = "https://files.pythonhosted.org/packages/b1/04/6acdbf17315f7b55f1937e3387acb89a3cddeb4995689553d064af8e92ab/aiohttp-3.14.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:270d3dace9ca2f10f0da5d8ebe519b7a310fc6112ed916e32df5866df0888553", size = 1912623, upload-time = "2026-07-23T01:56:50.605Z" },
{ url = "https://files.pythonhosted.org/packages/86/e6/438b0c79ca6f45eb9fd9817dd4c01a91919a38c0de5ee9e05e2b4dc0ece7/aiohttp-3.14.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3ae5b3a59436d089b5395d910121a390feed4d00578eb95a0fd1a329fe963100", size = 2005515, upload-time = "2026-07-23T01:56:53.153Z" },
{ url = "https://files.pythonhosted.org/packages/bb/6b/62cbd6577758699525f5c712d1ddef57d9875fbab0ae8d5f5a202fd598f8/aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2498f0fe69ead802f9675beca44a7c21c62fdaa4ec5145ea1c3ad6edbee29f85", size = 1879906, upload-time = "2026-07-23T01:56:55.818Z" },
{ url = "https://files.pythonhosted.org/packages/00/95/18bcbf830a21dc3aae24d8f6b6feaf3db1d2090242d00a7868db2ffb0b67/aiohttp-3.14.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a0dc483c00da8b673abbb367eb6f8d8f4bcec30eb58529ea13cb42e7fd2dfa33", size = 1675849, upload-time = "2026-07-23T01:56:58.861Z" },
{ url = "https://files.pythonhosted.org/packages/a9/19/47f4968659c5e23606c3790c80fc624e691c153d036148449ee84d31b287/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c7d3a97c678d34fc5b59da671ee9cd630096ddc643e7b5a30d54a2a6f3574d3f", size = 1843496, upload-time = "2026-07-23T01:57:01.591Z" },
{ url = "https://files.pythonhosted.org/packages/64/af/38c33c4dd82fddcb4e56c4653b6f1072a8edbc6b7fa15809f14932c41e2d/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f8fb78a83c9e5f741ca3a68cfb455c1f5bb83b4e7249a3848b3cd78d0a8563b0", size = 1827746, upload-time = "2026-07-23T01:57:05.131Z" },
{ url = "https://files.pythonhosted.org/packages/a1/9d/0537cda4885ac8f5b7053d164dd06312f4c483a4edcb8ee5b8aaf2a989bf/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:74ab5b6a9fb13e873e5a90946588baecaf488745e1db1a4a5c433f971f035098", size = 1853810, upload-time = "2026-07-23T01:57:08.043Z" },
{ url = "https://files.pythonhosted.org/packages/19/fe/26f9c5e6458385aa86497836b0dea6fb2f027827d63f37c7856cce9286ee/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd52f811e65f6fb634b1047159657c98f52b407f8efec907bcfc09da9a4c0a25", size = 1668895, upload-time = "2026-07-23T01:57:10.837Z" },
{ url = "https://files.pythonhosted.org/packages/ec/4c/618b1db9b9ba079b8875d2cdf78e7c4a3bf72903bd5850fee7dd9544600a/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:f0f177d1b195b9e06376cfd7d308d8a1b920909a609d03ac82a8c73bbb16d3b9", size = 1883833, upload-time = "2026-07-23T01:57:13.672Z" },
{ url = "https://files.pythonhosted.org/packages/94/c6/bd959bd1e4771f9fd944e9e436224c48c77b018b73b519b5aad346335bcc/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:498c6c623134f8e09a3c4e60bcd607a0b4590dd7dbf08dd40851b27cbb520ccb", size = 1844251, upload-time = "2026-07-23T01:57:16.593Z" },
{ url = "https://files.pythonhosted.org/packages/5e/19/08d41839658bdd44a0ed2480f3891705ecb487ce28c0dde62c9040c997e0/aiohttp-3.14.3-cp314-cp314t-win32.whl", hash = "sha256:b304db572b4368edd8dda8a2274f73156fe15558fca4a917cb8a09fc47af5963", size = 474180, upload-time = "2026-07-23T01:57:19.306Z" },
{ url = "https://files.pythonhosted.org/packages/99/5d/3cd6ef0a2b2851f7ab913b5b079334781bd50ff56a323e4454063377a080/aiohttp-3.14.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b20032766aedf6261c7a566585a40867d092ac03a0d81592d5370ef9b054f99b", size = 500528, upload-time = "2026-07-23T01:57:21.762Z" },
{ url = "https://files.pythonhosted.org/packages/a4/37/cfd1ed540a4d318da025590d96b728e63713c09e9377950fc655dadeb856/aiohttp-3.14.3-cp314-cp314t-win_arm64.whl", hash = "sha256:2e1161602f45a54de2ce0905243a95f58cb42dcd378402f3697f5e0b21e9d2e7", size = 469280, upload-time = "2026-07-23T01:57:24.241Z" },
]
[[package]]
name = "aiosignal"
version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "frozenlist" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
]
[[package]] [[package]]
name = "alembic" name = "alembic"
version = "1.19.1" version = "1.19.1"
@@ -174,15 +52,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
] ]
[[package]]
name = "attrs"
version = "26.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
]
[[package]] [[package]]
name = "backoff" name = "backoff"
version = "2.2.1" version = "2.2.1"
@@ -598,7 +467,7 @@ wheels = [
[[package]] [[package]]
name = "dagster" name = "dagster"
version = "1.13.19" version = "1.12.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "alembic" }, { name = "alembic" },
@@ -619,6 +488,7 @@ dependencies = [
{ name = "pywin32", marker = "sys_platform == 'win32'" }, { name = "pywin32", marker = "sys_platform == 'win32'" },
{ name = "requests" }, { name = "requests" },
{ name = "rich" }, { name = "rich" },
{ name = "setuptools" },
{ name = "six" }, { name = "six" },
{ name = "sqlalchemy" }, { name = "sqlalchemy" },
{ name = "structlog" }, { name = "structlog" },
@@ -630,14 +500,14 @@ dependencies = [
{ name = "universal-pathlib" }, { name = "universal-pathlib" },
{ name = "watchdog" }, { name = "watchdog" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/0b/3e/23ebd048231c36c7c063a7d972756268ef714deedb58366134a4d3c94ef7/dagster-1.13.19.tar.gz", hash = "sha256:c2b3d06c198dc3bd99be7b2c0ec5022c919b1acf20c058bf652f2498e0119ec7", size = 3629331, upload-time = "2026-08-21T15:12:15.466Z" } sdist = { url = "https://files.pythonhosted.org/packages/65/03/a5108fe3b882fe40baa1d34da6f2fe292ac5a75db9a8c7254de8b51a4e5a/dagster-1.12.8.tar.gz", hash = "sha256:38551907f2f261d63f290a364df9fea5abbf3e38cf64f837a8ef2afdd80f9d34", size = 1566204, upload-time = "2025-12-29T19:10:21.207Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/aa/46/8dbed1a3dc6299b5e92525ae29295ee264902343b0ad7297a4f537d4ef7f/dagster-1.13.19-py3-none-any.whl", hash = "sha256:22896569d6b371f42394ea36961e9fcc485f61c795aed2a733634979ce74f86b", size = 2025984, upload-time = "2026-08-21T15:12:12.95Z" }, { url = "https://files.pythonhosted.org/packages/a7/50/44e8fb3c2f67b252bbab83f4048a1f6f668c1e73eb8ca5fe19233b271786/dagster-1.12.8-py3-none-any.whl", hash = "sha256:102eb110762fb9c2db7443a7d5df2863f32054eb764db575074421ff16706813", size = 1950472, upload-time = "2025-12-29T19:10:18.876Z" },
] ]
[[package]] [[package]]
name = "dagster-graphql" name = "dagster-graphql"
version = "1.13.19" version = "1.12.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "dagster" }, { name = "dagster" },
@@ -646,50 +516,50 @@ dependencies = [
{ name = "requests" }, { name = "requests" },
{ name = "starlette" }, { name = "starlette" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/a1/fb/f0e76e0b276de31f84cc6687aeeb01cd27d15dbdf65d739400e3110bf691/dagster_graphql-1.13.19.tar.gz", hash = "sha256:30ffbfbb0e7b17a3c6dabfb2887ed0c5c8da13bccf239f1bc3e3252683f08484", size = 695728, upload-time = "2026-08-21T15:13:01.058Z" } sdist = { url = "https://files.pythonhosted.org/packages/c3/0e/515c2966532410a1d3b7427c00cc6fc3bc6061ef64327a25a437e20b070a/dagster_graphql-1.12.8.tar.gz", hash = "sha256:b732bcdc91fc4874b5aa2e3572f16b169764ddbf10498aabf14593f185b40473", size = 158881, upload-time = "2025-12-29T19:10:37.456Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/6e/09/ecd0a13a34a22930a723035d683960892d0b58d988bfc677c930233880d3/dagster_graphql-1.13.19-py3-none-any.whl", hash = "sha256:276a27cd1c09d226775cff509a31dfba582d430712c33af662695a1643c897c2", size = 228534, upload-time = "2026-08-21T15:12:59.746Z" }, { url = "https://files.pythonhosted.org/packages/f1/7b/81fe0eed6f88cd3084e25b8bc9090881e53a2eddd2de676c39a04c71d019/dagster_graphql-1.12.8-py3-none-any.whl", hash = "sha256:5ae8ea80d5bb94ef70ab6e87d3c8f55e1570fa8402ffffb1e85fa28c34502b7c", size = 206012, upload-time = "2025-12-29T19:10:36.294Z" },
] ]
[[package]] [[package]]
name = "dagster-k8s" name = "dagster-k8s"
version = "0.29.19" version = "0.28.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "dagster" }, { name = "dagster" },
{ name = "google-auth" }, { name = "google-auth" },
{ name = "kubernetes" }, { name = "kubernetes" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/94/06/38a258c3570d754df8c9768cc13fdb844046f7a4259b3ce64cd61cce0ccd/dagster_k8s-0.29.19.tar.gz", hash = "sha256:1d4b0e69f3fcff0704ffbce5a9554811163ff5df0a14059d566695041b928848", size = 309360, upload-time = "2026-08-21T15:22:56.758Z" } sdist = { url = "https://files.pythonhosted.org/packages/19/4d/19337f52238cd0ec071d381dc5030ff4928613f930c1e8601ef7f4a7e538/dagster_k8s-0.28.8.tar.gz", hash = "sha256:edd6af1476b3ef5c2d37da6217ea02f9756bda5fcd53e1c808aceab3e4662a4c", size = 51513, upload-time = "2025-12-29T19:21:42.738Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/e0/b5/0472da80caffa94dbebac98791fda6d51c9995889960e77a5dfb77db4a3e/dagster_k8s-0.29.19-py3-none-any.whl", hash = "sha256:cabe40918a895bd6c0ef8c12a875bd4eb68be9915ce337a618672593a35c2da4", size = 57796, upload-time = "2026-08-21T15:22:55.422Z" }, { url = "https://files.pythonhosted.org/packages/0a/cf/d324ca38d738c96af17e2a65c2337281dd2583ea8cc55179ccbec3688a6c/dagster_k8s-0.28.8-py3-none-any.whl", hash = "sha256:6864b26a38f8bb2048eabd2a2aa8a930ca57481b95407fe1143e8460d1cf652f", size = 56616, upload-time = "2025-12-29T19:21:41.653Z" },
] ]
[[package]] [[package]]
name = "dagster-pipes" name = "dagster-pipes"
version = "1.13.19" version = "1.12.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/43/f7/a7c6f1c347ae01d2eaa8dbdc36f927a71a19481f1d180c10d297b4044ba5/dagster_pipes-1.13.19.tar.gz", hash = "sha256:df0c3b3582dec0bdd2f19acd12672c2923d5601d35f66b222a2780d3c7247a0d", size = 149679, upload-time = "2026-08-21T15:12:49.982Z" } sdist = { url = "https://files.pythonhosted.org/packages/1f/63/2eb5eb7a18683d9feebb023140ed10935570d3c23f6b62aa50616fbb0bb0/dagster_pipes-1.12.8.tar.gz", hash = "sha256:0c590e3e42e2f94eaa013af7f8f049bca58962e4d013758f84d8608e4bc668a1", size = 21091, upload-time = "2025-12-29T19:10:32.306Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/e7/54/0dc0f7404eca8c9759336f3cee562b59851197e3c7c1b65ce5047d774165/dagster_pipes-1.13.19-py3-none-any.whl", hash = "sha256:3a4af8d4e72f1b8da673fabf53d1e598236e1274f77327de790e31aab00b8df8", size = 20242, upload-time = "2026-08-21T15:12:48.903Z" }, { url = "https://files.pythonhosted.org/packages/7b/82/6fd7fede962812656f6f279e43e45b62f42c1e9c8f0d6b745ab3bb43ee87/dagster_pipes-1.12.8-py3-none-any.whl", hash = "sha256:12fa5049c5719b2b83c8702031779833cc5f34e8da270cf8483958378ba104c1", size = 20839, upload-time = "2025-12-29T19:10:31.051Z" },
] ]
[[package]] [[package]]
name = "dagster-postgres" name = "dagster-postgres"
version = "0.29.19" version = "0.28.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "dagster" }, { name = "dagster" },
{ name = "psycopg2-binary" }, { name = "psycopg2-binary" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/e4/28/5c59e5227268d0330837f3dfe699e6733a85fc6ab0638c8c7e972a4668ad/dagster_postgres-0.29.19.tar.gz", hash = "sha256:3cd350b716faf492210f9541bbcdc70eea90df3b0a69cd8d4dff514af1ac6b31", size = 406345, upload-time = "2026-08-21T15:22:18.789Z" } sdist = { url = "https://files.pythonhosted.org/packages/e0/54/0f681df1d31f88dc4ef514a323957bdc139af3ff0df006010131a6940cef/dagster_postgres-0.28.8.tar.gz", hash = "sha256:3a5957445792294000454b2a56b81c2e607a18248abc522ccf53cca794e5f682", size = 16456, upload-time = "2025-12-29T19:19:23.51Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/db/49/8f62e575a5a560ded18247b355a4a037a0fea501fdcd86bc06a422f81093/dagster_postgres-0.29.19-py3-none-any.whl", hash = "sha256:8a89aecbec1a0e4bea6abe766ffa9f3e06b9779885b5914f8d072b1bebd9c89f", size = 25558, upload-time = "2026-08-21T15:22:17.716Z" }, { url = "https://files.pythonhosted.org/packages/75/80/d063bf1d4a489b84a33b84c138822b15ae01729082db0b9d11e895549bf6/dagster_postgres-0.28.8-py3-none-any.whl", hash = "sha256:ae21b163d6ba2c2b5b73b724ab5b0b6ef4434aa6ed4e7106fa6a91fa03f969a0", size = 22944, upload-time = "2025-12-29T19:19:22.464Z" },
] ]
[[package]] [[package]]
name = "dagster-shared" name = "dagster-shared"
version = "1.13.19" version = "1.12.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "packaging" }, { name = "packaging" },
@@ -699,14 +569,14 @@ dependencies = [
{ name = "tomlkit" }, { name = "tomlkit" },
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/6b/d3/5c6090138b27a51c9f92722a05e4fe0f1eebbf1f14badd8ef5d4e32f84ba/dagster_shared-1.13.19.tar.gz", hash = "sha256:76f920b20866e28092fe02983dca4bfba55bd8596b5f5c20429343dfb5d7a39a", size = 124096, upload-time = "2026-08-21T15:27:12.517Z" } sdist = { url = "https://files.pythonhosted.org/packages/78/5c/7f5463895c357117bf9285452e5525c54f4aca02ac331b20817d08cdd938/dagster_shared-1.12.8.tar.gz", hash = "sha256:b22beeb43dd0a6da8744a2409fd1c56f0864da81fb7a59b7b97db2d520b0eff8", size = 78154, upload-time = "2025-12-29T19:20:42.532Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/2a/5d/938ba2c23f0b19938b1bad63f03a2bb12a1c43175c02db99dbc3c024542f/dagster_shared-1.13.19-py3-none-any.whl", hash = "sha256:35653847a031ebcf4f9e1b37b4f509938d18adf1088b2331a44182ccf124a898", size = 96420, upload-time = "2026-08-21T15:27:11.392Z" }, { url = "https://files.pythonhosted.org/packages/54/55/15b8aa49fd4b9cf0eccd13b19a63b024a782fea1890667c0db9045f84793/dagster_shared-1.12.8-py3-none-any.whl", hash = "sha256:1522a8da2f821014e9307bd03f5e9d9d9dbe657d74de3742501f3538b8d36572", size = 91408, upload-time = "2025-12-29T19:20:41.609Z" },
] ]
[[package]] [[package]]
name = "dagster-webserver" name = "dagster-webserver"
version = "1.13.19" version = "1.12.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "click" }, { name = "click" },
@@ -715,9 +585,9 @@ dependencies = [
{ name = "starlette" }, { name = "starlette" },
{ name = "uvicorn", extra = ["standard"] }, { name = "uvicorn", extra = ["standard"] },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/40/9c/12017b879d2e8893fe749617e0154e03d0edbbee9591d419bfa865b1669c/dagster_webserver-1.13.19.tar.gz", hash = "sha256:4192e80321623975b3cff4623aba48a4dbc63dc48d01f37f4be160a31d3dffa9", size = 12366742, upload-time = "2026-08-21T15:20:08.722Z" } sdist = { url = "https://files.pythonhosted.org/packages/60/3d/f96da5c164b337b763b75e0c084bd52be95eaa2a60d021261e90d9d06b10/dagster_webserver-1.12.8.tar.gz", hash = "sha256:c12ed724cc6258f948cd0e3800cf9ff01e986e73b9eca6e923cf75a2f98aa5de", size = 12241193, upload-time = "2025-12-29T19:18:24.8Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/6a/08/dec5071faa1e0c33f0b78c1ac4ff37a37ab469f8e93451f4e972c6ef9828/dagster_webserver-1.13.19-py3-none-any.whl", hash = "sha256:65115560fd197a6ead94e4a25d141447d10238fc650540f0f0fa61cd48c3d4ad", size = 12516446, upload-time = "2026-08-21T15:20:06.387Z" }, { url = "https://files.pythonhosted.org/packages/cb/94/1ba8d099c25e2a14a0d3923c137ea971827f8dd3fae475310b6f77917c21/dagster_webserver-1.12.8-py3-none-any.whl", hash = "sha256:49a64df19d420c398593ff7582e1dd8cf0dbf02a9752e52aed6e758490364de2", size = 12582830, upload-time = "2025-12-29T19:18:22.46Z" },
] ]
[[package]] [[package]]
@@ -741,10 +611,10 @@ dev = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "dagster" }, { name = "dagster", specifier = "==1.12.8" },
{ name = "dagster-k8s", specifier = ">=0.27.16" }, { name = "dagster-k8s", specifier = "==0.28.8" },
{ name = "dagster-postgres", specifier = ">=0.27.16" }, { name = "dagster-postgres", specifier = "==0.28.8" },
{ name = "dagster-webserver", specifier = ">=1.11.16" }, { name = "dagster-webserver", specifier = "==1.12.8" },
{ name = "pip", specifier = ">=26.1.2" }, { name = "pip", specifier = ">=26.1.2" },
{ name = "pydantic", specifier = ">=2.0" }, { name = "pydantic", specifier = ">=2.0" },
] ]
@@ -782,95 +652,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl", hash = "sha256:22e58ca3b1ae3b98993b762d7338367ae64fe50252bf78d59da3bfebcdf1cedd", size = 99864, upload-time = "2026-08-23T17:37:53.913Z" }, { url = "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl", hash = "sha256:22e58ca3b1ae3b98993b762d7338367ae64fe50252bf78d59da3bfebcdf1cedd", size = 99864, upload-time = "2026-08-23T17:37:53.913Z" },
] ]
[[package]]
name = "frozenlist"
version = "1.8.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" },
{ url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" },
{ url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" },
{ url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" },
{ url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" },
{ url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" },
{ url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" },
{ url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" },
{ url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" },
{ url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" },
{ url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" },
{ url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" },
{ url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" },
{ url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" },
{ url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" },
{ url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" },
{ url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" },
{ url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" },
{ url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" },
{ url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" },
{ url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" },
{ url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" },
{ url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" },
{ url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" },
{ url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" },
{ url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" },
{ url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" },
{ url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" },
{ url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" },
{ url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" },
{ url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" },
{ url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" },
{ url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" },
{ url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" },
{ url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" },
{ url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" },
{ url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" },
{ url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" },
{ url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" },
{ url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" },
{ url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" },
{ url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" },
{ url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" },
{ url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" },
{ url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" },
{ url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" },
{ url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" },
{ url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" },
{ url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" },
{ url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" },
{ url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" },
{ url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" },
{ url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" },
{ url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" },
{ url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" },
{ url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" },
{ url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" },
{ url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" },
{ url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" },
{ url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" },
{ url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" },
{ url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" },
{ url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" },
{ url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" },
{ url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" },
{ url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" },
{ url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" },
{ url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" },
{ url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" },
{ url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" },
{ url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" },
{ url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" },
{ url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" },
{ url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" },
{ url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" },
{ url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" },
{ url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" },
{ url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" },
{ url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" },
{ url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" },
{ url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
]
[[package]] [[package]]
name = "fsspec" name = "fsspec"
version = "2026.7.0" version = "2026.7.0"
@@ -1148,12 +929,12 @@ wheels = [
[[package]] [[package]]
name = "kubernetes" name = "kubernetes"
version = "36.0.3" version = "34.1.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "aiohttp" },
{ name = "certifi" }, { name = "certifi" },
{ name = "durationpy" }, { name = "durationpy" },
{ name = "google-auth" },
{ name = "python-dateutil" }, { name = "python-dateutil" },
{ name = "pyyaml" }, { name = "pyyaml" },
{ name = "requests" }, { name = "requests" },
@@ -1162,9 +943,9 @@ dependencies = [
{ name = "urllib3" }, { name = "urllib3" },
{ name = "websocket-client" }, { name = "websocket-client" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/ca/57/b07b96353f902aa1bdbe00e878e3a12a137977d03a962479785576aa8ec9/kubernetes-36.0.3.tar.gz", hash = "sha256:36993ed25ce59b789c9341473a228fcf268504a2fec7c2b2b1531d73072e5ce7", size = 2337528, upload-time = "2026-07-13T20:38:12.128Z" } sdist = { url = "https://files.pythonhosted.org/packages/ef/55/3f880ef65f559cbed44a9aa20d3bdbc219a2c3a3bac4a30a513029b03ee9/kubernetes-34.1.0.tar.gz", hash = "sha256:8fe8edb0b5d290a2f3ac06596b23f87c658977d46b5f8df9d0f4ea83d0003912", size = 1083771, upload-time = "2025-09-29T20:23:49.283Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/30/a96d47df739689ac0001ade0afefc16e3b477fc2fb426b568515fdc8afce/kubernetes-36.0.3-py2.py3-none-any.whl", hash = "sha256:8fde9241c4b298e6374a069dcf728359b4e72c2fb29489a975ba4e1c047cf10f", size = 4618066, upload-time = "2026-07-13T20:38:10.172Z" }, { url = "https://files.pythonhosted.org/packages/ca/ec/65f7d563aa4a62dd58777e8f6aa882f15db53b14eb29aba0c28a20f7eb26/kubernetes-34.1.0-py2.py3-none-any.whl", hash = "sha256:bffba2272534e224e6a7a74d582deb0b545b7c9879d2cd9e4aae9481d1f2cc2a", size = 2008380, upload-time = "2025-09-29T20:23:47.684Z" },
] ]
[[package]] [[package]]
@@ -1896,6 +1677,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
] ]
[[package]]
name = "setuptools"
version = "84.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz", hash = "sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73", size = 1168449, upload-time = "2026-08-08T18:27:58.365Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl", hash = "sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670", size = 818216, upload-time = "2026-08-08T18:27:56.719Z" },
]
[[package]] [[package]]
name = "six" name = "six"
version = "1.17.0" version = "1.17.0"
@@ -2091,11 +1881,11 @@ wheels = [
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "2.7.0" version = "2.3.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload-time = "2024-12-22T07:47:30.032Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload-time = "2024-12-22T07:47:28.074Z" },
] ]
[[package]] [[package]]

View File

@@ -0,0 +1,182 @@
# Cluster probe for the loosely coupled Kubernetes transport.
#
# Runs `loosely_coupled_k8s_job` from a single throwaway pod. The point is to
# prove the part of this service that no test can reach: that the dispatching
# process creates payload Jobs and that messages come back over the pod log
# stream. It clears readiness checks L4-L9 in one run.
#
# Deliberately NOT a Dagster deployment. No webserver, no daemon, no database,
# no code location registration. That sidesteps the control-plane version skew -
# the pod is its own control plane, so the 1.13.19 images here have nothing to be
# compatible with. Everything lives in one namespace you delete afterwards.
#
# --- Before applying -------------------------------------------------------
#
# Credentials, only if your registry needs them. The Gitea images referenced
# below do NOT: a bare GET returns 401, but that is the start of the Docker
# token handshake, and completing it anonymously returns the manifest. A probe
# pod carrying no credentials pulled and ran on the sandbox on 2026-08-31.
#
# If you point this at a registry that does require authentication, remember the
# payload Jobs need it too. PipesK8sClient sets no serviceAccountName, so they
# run as `default` and inherit nothing from the pod below; patch that account or
# pass imagePullSecrets through base_pod_spec in dispatch_external_work_k8s. A
# payload pod that cannot pull leaves the op waiting until pod_wait_timeout,
# which reads like a hung workload rather than a missing credential.
#
# kubectl apply -f yaml/loosely-coupled/probe-pipes-k8s.yaml
#
# On sandbox-cat-dat use yaml/sandbox/probe-pipes-k8s-sandbox.yaml instead: that
# cluster's access is Rancher project-scoped, so this file's namespace and RBAC
# cannot be created there. The sandbox variant needs neither.
#
# `--dry-run=server` reports "namespaces distexec-probe not found" for the four
# namespaced objects. That is the dry run declining to create the namespace it
# would need, not a fault in the manifests; `--dry-run=client` passes clean.
#
# LIMITATION under a restricted Pod Security namespace. This pod satisfies the
# restricted standard, but the payload Jobs do not: PipesK8sClient builds those
# pod specs and this service passes no securityContext through base_pod_spec, so
# such a namespace would admit the dispatcher and reject every payload it
# creates. Leave the probe namespace unlabelled, or add the fields to
# base_pod_spec in dispatch_external_work_k8s first.
#
# --- Reading the result ----------------------------------------------------
#
# kubectl -n distexec-probe logs -f job/pipes-probe
# kubectl -n distexec-probe get jobs -l app.kubernetes.io/name=distributed-execution-payload
#
# Success is RUN_SUCCESS plus four payload Jobs, one per work unit. The
# summarise_results output carries contributing_workers; on a cluster those
# should be four distinct pod hostnames, which is the claim the guide makes and
# a laptop cannot demonstrate.
#
# A run that reaches RUN_FAILURE with "no pipes messages received" means the
# payload ran but its log stream never came back - check the pods/log rule
# below before suspecting the payload.
#
# --- Teardown --------------------------------------------------------------
#
# kubectl delete namespace distexec-probe
#
# NOT CLUSTER-VERIFIED. Written against the published images and the RBAC the
# pipes client is documented to need, but not yet applied to a cluster.
apiVersion: v1
kind: Namespace
metadata:
name: distexec-probe
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: pipes-dispatcher
namespace: distexec-probe
imagePullSecrets:
- name: gitea-registry
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pipes-dispatcher
namespace: distexec-probe
rules:
- apiGroups: ["batch"]
resources: ["jobs", "jobs/status"]
verbs: ["create", "get", "list", "watch", "delete"]
# pods/log is the message channel for PipesK8sPodLogsMessageReader, not just
# an observability convenience. Without it the payload runs to completion and
# reports nothing, and the op fails on an empty message list.
- apiGroups: [""]
resources: ["pods", "pods/log", "pods/status"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pipes-dispatcher
namespace: distexec-probe
subjects:
- kind: ServiceAccount
name: pipes-dispatcher
namespace: distexec-probe
roleRef:
kind: Role
name: pipes-dispatcher
apiGroup: rbac.authorization.k8s.io
---
apiVersion: batch/v1
kind: Job
metadata:
name: pipes-probe
namespace: distexec-probe
spec:
# One shot. A retry would obscure which attempt produced which payload Jobs.
backoffLimit: 0
activeDeadlineSeconds: 1800
template:
metadata:
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
spec:
restartPolicy: Never
serviceAccountName: pipes-dispatcher
# A service account with automountServiceAccountToken: false - which the
# platform's dagster-svc-account uses - leaves the pipes client selecting
# in-cluster auth and then failing on "Service token file does not exist".
automountServiceAccountToken: true
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
# Makes the emptyDir writable by UID 1000, which DAGSTER_HOME needs.
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: dispatcher
image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:5122da4691f9
imagePullPolicy: IfNotPresent
# Satisfies the restricted Pod Security standard. The int cluster did
# not enforce it when this was written and the sandbox was not checked;
# a cluster that does enforce it rejects the pod outright.
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command:
- dagster
- job
- execute
- -f
- src/distributed_execution/repository.py
- -j
- loosely_coupled_k8s_job
env:
- name: DAGSTER_HOME
value: /dagster-home
# Must be the same commit as the image above.
- name: PIPES_PAYLOAD_IMAGE
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution-payload:5122da4691f9
- name: PIPES_PAYLOAD_NAMESPACE
value: distexec-probe
volumeMounts:
- name: dagster-home
mountPath: /dagster-home
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
volumes:
# The job runs on multiprocess_executor, so the instance has to be a real
# sqlite instance on disk rather than an ephemeral one.
- name: dagster-home
emptyDir: {}

View File

@@ -6,6 +6,18 @@
# Contrast with yaml/tightly-coupled/values-run-launcher.yaml: there, every # Contrast with yaml/tightly-coupled/values-run-launcher.yaml: there, every
# execution pod needed S3 and Vault credentials. Here the payload needs none - # execution pod needed S3 and Vault credentials. Here the payload needs none -
# only the dispatching pod does. # only the dispatching pod does.
#
# VERSION LOCK. The payload tag below must equal the code location image tag in
# yaml/values-dagster-distributed-execution.yaml. The two images share a commit:
# the dispatching op and payload/work.py agree on the `units` extras key and on
# the custom-message shape, and nothing at runtime checks that agreement. A
# mismatched pair surfaces as "no pipes messages received", which reads like a
# broken message channel rather than a version skew.
#
# For values that work today, see yaml/sandbox/values-sandbox-gitea.yaml. The
# shared GitLab pipeline (ds.gitlab-ci.yml) builds exactly one image per project -
# $CI_REGISTRY_IMAGE from the root Dockerfile - so the payload reference below
# resolves only once that pipeline learns to build a second image.
dagster: dagster:
dagster-user-deployments: dagster-user-deployments:
@@ -14,7 +26,8 @@ dagster:
envSecrets: [] envSecrets: []
env: env:
- name: PIPES_PAYLOAD_IMAGE - name: PIPES_PAYLOAD_IMAGE
value: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/payload:0.1.0 # DO NOT CHANGE the tag - replaced automatically by the pipeline before releasing
value: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/distributed-execution/payload:0.0.0
- name: PIPES_PAYLOAD_NAMESPACE - name: PIPES_PAYLOAD_NAMESPACE
value: dagster value: dagster
@@ -27,6 +40,7 @@ dagster:
containerConfig: containerConfig:
env: env:
- name: PIPES_PAYLOAD_IMAGE - name: PIPES_PAYLOAD_IMAGE
value: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/payload:0.1.0 # DO NOT CHANGE the tag - replaced automatically by the pipeline before releasing
value: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/distributed-execution/payload:0.0.0
- name: PIPES_PAYLOAD_NAMESPACE - name: PIPES_PAYLOAD_NAMESPACE
value: dagster value: dagster

View File

@@ -0,0 +1,161 @@
# T6/T7 probe - tightly coupled via k8s_job_executor, one pod per step.
#
# This is the invasive one. Unlike the pipes probe it writes to the platform's
# live metadata database, because that is what tightly coupled means: every step
# pod opens the database itself, so they must share instance storage. Safe only
# because the images are pinned to dagster 1.12.8, exactly matching the control
# plane, so no schema migration can be triggered.
#
# Two things the loosely coupled probe did not need:
#
# 1. Shared instance storage. DAGSTER_HOME is copied from the platform's
# `dagster-instance` ConfigMap into a writable volume, so run and event
# storage are the same Postgres the platform uses. Step pods get the same
# config via the run launcher's `instance_config_map`.
#
# 2. A shared I/O manager. The default writes step outputs to pod-local disk,
# which under this executor means a downstream step cannot read an upstream
# output. base_dir is redirected to the RWX `dagster-shared-pvc` the
# launcher already declares.
#
# The run config lives in its own ConfigMap rather than a heredoc inside the
# container command. A heredoc nested in a YAML block scalar silently produced an
# empty file on the first attempt, and an empty run config is valid YAML, so the
# run started and only failed later with "No image included in either executor
# config or the job" - a confusing distance from the actual cause. The command
# echoes the config before using it so that failure mode cannot recur silently.
#
# --- Running ---------------------------------------------------------------
#
# kubectl -n dataprovider01 apply -f yaml/sandbox/probe-k8s-executor-sandbox.yaml
# kubectl -n dataprovider01 logs -f job/distexec-k8sexec-probe
# kubectl -n dataprovider01 get jobs -l dagster/job=tightly_coupled_k8s_job # T6
#
# --- Teardown --------------------------------------------------------------
#
# kubectl -n dataprovider01 delete job distexec-k8sexec-probe
# kubectl -n dataprovider01 delete jobs -l dagster/job=tightly_coupled_k8s_job
# kubectl -n dataprovider01 delete cm distexec-probe-run-config
#
# The run itself stays in the platform's Dagster database and will be visible in
# its UI. That is not reversible with kubectl.
apiVersion: v1
kind: ConfigMap
metadata:
name: distexec-probe-run-config
namespace: dataprovider01
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
data:
run-config.yaml: |
execution:
config:
job_namespace: dataprovider01
job_image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:3f8175a17f0a
service_account_name: dagster-svc-account
image_pull_policy: IfNotPresent
max_concurrent: 2
# Step pods inherit DAGSTER_HOME from the launching process otherwise,
# which points at a volume only that pod has.
env_vars:
- DAGSTER_HOME=/dagster/shared/distexec-probe/home
volumes:
- name: dagster-shared-storage
persistent_volume_claim:
claim_name: dagster-shared-pvc
volume_mounts:
- name: dagster-shared-storage
mount_path: /dagster/shared
step_k8s_config:
pod_spec_config:
automount_service_account_token: true
---
apiVersion: batch/v1
kind: Job
metadata:
name: distexec-k8sexec-probe
namespace: dataprovider01
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
spec:
backoffLimit: 0
activeDeadlineSeconds: 1800
template:
metadata:
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
spec:
restartPolicy: Never
serviceAccountName: dagster-svc-account
automountServiceAccountToken: true
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: runner
image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:3f8175a17f0a
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
env:
# On the RWX volume, not a pod-local one: the default I/O manager writes
# step outputs under $DAGSTER_HOME/storage, and every step pod has to
# read what the previous one wrote.
- name: DAGSTER_HOME
value: /dagster/shared/distexec-probe/home
# How the chart tells a code location which image its steps run as.
- name: DAGSTER_CURRENT_IMAGE
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:3f8175a17f0a
- name: DAGSTER_PG_PASSWORD
valueFrom:
secretKeyRef:
name: dagster-postgresql-secret
key: postgresql-password
command:
- sh
- -c
- |
set -e
mkdir -p "$DAGSTER_HOME"
cp /instance-cm/dagster.yaml "$DAGSTER_HOME/dagster.yaml"
echo "===== run config in use ====="
cat /run-config/run-config.yaml
echo "===== T6/T7: tightly_coupled_k8s_job ====="
dagster job execute -f src/distributed_execution/repository.py -j tightly_coupled_k8s_job -c /run-config/run-config.yaml
volumeMounts:
- name: instance-cm
mountPath: /instance-cm
readOnly: true
- name: run-config
mountPath: /run-config
readOnly: true
- name: dagster-shared-storage
mountPath: /dagster/shared
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
volumes:
- name: instance-cm
configMap:
name: dagster-instance
- name: run-config
configMap:
name: distexec-probe-run-config
- name: dagster-shared-storage
persistentVolumeClaim:
claimName: dagster-shared-pvc

View File

@@ -0,0 +1,124 @@
# Sandbox variant of the pipes cluster probe.
#
# Runs `loosely_coupled_k8s_job` as a single Job in dataprovider01, reusing the
# platform's own dagster-svc-account. Use this instead of
# yaml/loosely-coupled/probe-pipes-k8s.yaml on sandbox-cat-dat.
#
# WHY IT LOOKS DIFFERENT. The generic probe creates its own namespace, service
# account and RBAC. That cannot run here: sandbox access is Rancher
# project-scoped, so a freshly created namespace belongs to no project and the
# creator has no rights inside it, and `create roles` is denied in every
# namespace. Verified with `kubectl auth can-i`, not assumed.
#
# It does not need them anyway. The `dagster-role` bound to dagster-svc-account
# already grants batch/jobs (full verbs), jobs/status, pods, events, and
# pods/log - exactly the set the pipes client needs. Readiness checks L5 and L6
# therefore already pass on this cluster; read the live Role to confirm:
#
# kubectl -n dataprovider01 get role dagster-role -o yaml
#
# WHAT THIS COSTS. Unlike the generic probe this is NOT isolated. It borrows a
# live service account and leaves payload Jobs in a shared namespace until they
# are deleted. Nothing it does is persistent, but it is visible to anyone else
# working in dataprovider01.
#
# --- Credentials: none needed ----------------------------------------------
#
# Both Gitea images are anonymously pullable. A bare GET to the registry returns
# 401, which looks like a refusal but is just the start of the Docker token
# handshake; completing it anonymously and re-requesting the manifest returns
# 200 for both images. Verify with:
#
# TOK=$(curl -sS "https://gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/v2/token?service=container_registry&scope=repository:j.r/distributed-execution:pull" | jq -r .token)
# curl -sS -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $TOK" \
# https://gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/v2/j.r/distributed-execution/manifests/5122da4691f9
#
# This also means the payload Jobs need nothing: they run as the `default`
# service account, which carries no pull secret, and do not need one.
#
# --- Running ---------------------------------------------------------------
#
# kubectl -n dataprovider01 apply -f yaml/sandbox/probe-pipes-k8s-sandbox.yaml
# kubectl -n dataprovider01 logs -f job/distexec-pipes-probe
# kubectl -n dataprovider01 get jobs -l app.kubernetes.io/name=distributed-execution-payload
#
# --- Teardown --------------------------------------------------------------
#
# kubectl -n dataprovider01 delete job distexec-pipes-probe
# kubectl -n dataprovider01 delete jobs -l app.kubernetes.io/name=distributed-execution-payload
#
# VERIFIED 2026-08-31 on sandbox-cat-dat / dataprovider01. Run
# cff9b348-bfc3-4ac1-ab51-a94892b8e3a0 reached RUN_SUCCESS: four payload Jobs,
# four distinct payload pod hostnames in contributing_hosts, messages returned
# over the pod log stream. Checks L4-L10 pass. Torn down afterwards; the
# namespace was left as it was found.
apiVersion: batch/v1
kind: Job
metadata:
name: distexec-pipes-probe
namespace: dataprovider01
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
spec:
backoffLimit: 0
activeDeadlineSeconds: 1800
template:
metadata:
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
spec:
restartPolicy: Never
# Already holds jobs + pods/log; this probe grants itself nothing.
serviceAccountName: dagster-svc-account
# dagster-svc-account sets automountServiceAccountToken: false, so every
# pod that uses it must opt back in - the chart does this for its own
# deployments. Without it the pipes client picks in-cluster auth correctly
# and then fails on "Service token file does not exist".
automountServiceAccountToken: true
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: dispatcher
image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:5122da4691f9
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command:
- dagster
- job
- execute
- -f
- src/distributed_execution/repository.py
- -j
- loosely_coupled_k8s_job
env:
- name: DAGSTER_HOME
value: /dagster-home
- name: PIPES_PAYLOAD_IMAGE
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution-payload:5122da4691f9
- name: PIPES_PAYLOAD_NAMESPACE
value: dataprovider01
volumeMounts:
- name: dagster-home
mountPath: /dagster-home
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
volumes:
- name: dagster-home
emptyDir: {}

View File

@@ -0,0 +1,99 @@
# Tightly coupled probe for sandbox-cat-dat - the part that is safe to run.
#
# Covers T4 and proves the run pod can reach the metadata database, using a
# LOCAL SQLite instance. It deliberately does NOT write to the platform's
# Postgres. See "What this cannot cover" below.
#
# Runs three things in one pod:
# 1. A TCP probe to Postgres using this repository's own check_tcp_reachable.
# 2. tightly_coupled_in_process_job - single process, no fan-out.
# 3. tightly_coupled_local_job - multiprocess fan-out inside one pod (T4).
#
# --- What this cannot cover ------------------------------------------------
#
# T6 and T7 need `tightly_coupled_k8s_job`, and that cannot use a local SQLite
# instance: k8s_job_executor puts every step in its own pod, and each step pod
# opens the metadata database itself. That is the definition of tightly coupled.
# The step pods must therefore share instance storage, which means Postgres.
#
# The only Postgres available is `dataprovider01_dagster`, the platform's live
# metadata database, and these images carry dagster 1.13.19 against a control
# plane on 1.12.8. Pointing a newer Dagster at an older schema is not a safe
# operation on a shared database: at best it refuses to start with a schema
# mismatch, and it is not worth finding out the worse case on someone else's
# instance. Pin dagster to the control plane version and rebuild before trying.
#
# T1 is only partly covered. Its stated evidence expects DAGSTER_POSTGRES_HOST,
# DAGSTER_POSTGRES_USER and DAGSTER_POSTGRES_DB in the pod environment; the
# platform sets none of them - it passes DAGSTER_PG_PASSWORD and bakes the rest
# into dagster.yaml. Left unset here deliberately, so the run reports the real
# deployment's state rather than a flattering one.
#
# --- Running ---------------------------------------------------------------
#
# kubectl -n dataprovider01 apply -f yaml/sandbox/probe-tightly-coupled-sandbox.yaml
# kubectl -n dataprovider01 logs -f job/distexec-tc-probe
# kubectl -n dataprovider01 delete job distexec-tc-probe
apiVersion: batch/v1
kind: Job
metadata:
name: distexec-tc-probe
namespace: dataprovider01
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
spec:
backoffLimit: 0
activeDeadlineSeconds: 1800
template:
metadata:
labels:
app.kubernetes.io/name: distributed-execution
app.kubernetes.io/component: probe
spec:
restartPolicy: Never
serviceAccountName: dagster-svc-account
automountServiceAccountToken: true
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: runner
image: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution:5122da4691f9
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
env:
- name: DAGSTER_HOME
value: /dagster-home
command:
- sh
- -c
- |
echo "===== T1: can this pod reach the metadata database? ====="
python -c "from distributed_execution.preflight import check_tcp_reachable; print(check_tcp_reachable('pg-cluster.common01.svc.cluster.local', 5432))"
echo "===== tightly_coupled_in_process_job ====="
dagster job execute -f src/distributed_execution/repository.py -j tightly_coupled_in_process_job
echo "===== T4: tightly_coupled_local_job ====="
dagster job execute -f src/distributed_execution/repository.py -j tightly_coupled_local_job
volumeMounts:
- name: dagster-home
mountPath: /dagster-home
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
volumes:
- name: dagster-home
emptyDir: {}

View File

@@ -0,0 +1,60 @@
# Sandbox deployment values - Gitea registry.
#
# NOT CLUSTER-VERIFIED. The images and the registry behaviour here are confirmed
# - a probe pod ran from them on the sandbox on 2026-08-31 - but these values
# have never been applied as a code location. Registering this service against
# the sandbox Dagster is still blocked on the version skew below.
#
# VERSION SKEW, unresolved. These images carry dagster 1.13.19 (requirements.txt
# pins no upper bound, so the build took whatever was current). The sandbox
# control plane is 1.12.8. A code server is a gRPC server the webserver and
# daemon call into, so the two versions have to be compatible; a minor-version
# gap is not a supported configuration. Pin dagster to the control plane version
# and rebuild before reading a failure here as a bug in this service.
#
# Use these instead of the code.europa.eu references in
# yaml/values-dagster-distributed-execution.yaml and
# yaml/loosely-coupled/values-pipes-payload.yaml when deploying to the
# dataprovider01 sandbox. Both images were built and published by a Gitea Actions
# workflow held in the sandbox Gitea mirror of this repository, not here.
#
# The tag below is a short commit SHA and is the same for both images. That is
# the version lock: the code location and the payload it dispatches must come
# from one commit. Bump both together or not at all.
#
# The Gitea images are anonymously pullable, so NO pull secret is needed. A bare
# GET to the registry returns 401, which reads as a refusal but is only the start
# of the Docker token handshake; completing it anonymously and re-requesting the
# manifest returns 200 for both images. This was confirmed on 2026-08-31, and a
# probe pod carrying no credentials pulled and ran on the sandbox.
#
# An earlier revision of this file required a pull secret on both the deployment
# and the run launcher. That was wrong, and wrong in an expensive direction: it
# sent the reader looking for credentials that do not exist.
dagster:
dagster-user-deployments:
deployments:
- name: distributed-execution
image:
repository: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution
tag: 5122da4691f9
pullPolicy: IfNotPresent
env:
- name: PIPES_PAYLOAD_IMAGE
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution-payload:5122da4691f9
# The sandbox release is named `dagster` but lives in dataprovider01;
# there is no namespace called `dagster` on that cluster.
- name: PIPES_PAYLOAD_NAMESPACE
value: dataprovider01
runLauncher:
config:
k8sRunLauncher:
runK8sConfig:
containerConfig:
env:
- name: PIPES_PAYLOAD_IMAGE
value: gitea.dataprovider01.sandbox-cat-dat.simpl-europe.eu/j.r/distributed-execution-payload:5122da4691f9
- name: PIPES_PAYLOAD_NAMESPACE
value: dataprovider01

View File

@@ -13,8 +13,8 @@ dagster:
config: config:
k8sRunLauncher: k8sRunLauncher:
# Namespace the run pods land in. Must be a namespace whose NetworkPolicy # Namespace the run pods land in. Must be a namespace whose NetworkPolicy
# permits egress to Postgres, object storage and Vault - see AC1 # permits egress to Postgres, object storage and Vault - see the
# prerequisites in the user guide. # prerequisites in section 2.3 of the user guide.
jobNamespace: dagster jobNamespace: dagster
# Surfaces step failures as pod failures so kubectl and Dagster agree. # Surfaces step failures as pod failures so kubectl and Dagster agree.

View File

@@ -28,7 +28,9 @@ dagster:
image: image:
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
repository: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution # $CI_REGISTRY_IMAGE for this project - the pipeline pushes here, so anything
# else is a reference to an image nobody builds.
repository: code.europa.eu:4567/simpl/simpl-open/data/supporting-data-services/distributed-execution/distributed-execution
tag: 0.0.0 # DO NOT CHANGE - replaced automatically by the pipeline before releasing tag: 0.0.0 # DO NOT CHANGE - replaced automatically by the pipeline before releasing
port: 4000 port: 4000