Rexec Developer

Developer Guide

Set up a local development stack, understand the codebase structure, and contribute to the SciDx Rexec ecosystem.

Source Repositories

The Rexec ecosystem is spread across four GitHub repositories. Each has a distinct responsibility:

RepoRoleLanguageLink
ndp-ep-py NDP Endpoint Python client library. High-level interface users interact with; pulls in scidx-rexec as an extra. Python sci-ndp/ndp-ep-py ↗
SciDx-rexec The rexec client library. Handles ZeroMQ connection to broker, serialization, and job dispatch. Python sci-ndp/SciDx-rexec ↗
SciDx-rexec-server The per-user rexec server pod. Connects to the broker as a worker and executes dispatched functions. Python sci-ndp/SciDx-rexec-server ↗
SciDx-rexec-broker The ZeroMQ message broker. Routes messages between many clients and many server pods. Python / K8s sci-ndp/SciDx-rexec-broker ↗
rexec-server-k8s-deployment-api FastAPI service that provisions/destroys rexec-server pods in Kubernetes on demand. Python / FastAPI sci-ndp/rexec-server-k8s-deployment-api ↗
ep-api NDP Endpoint API (FastAPI). Provides dataset catalog, auth integration, and Rexec spawn API address. Python / FastAPI national-data-platform/ep-api ↗

Repository Map

This meta-repo (sci-ndp/rexec) contains documentation, helm charts, and user notebooks. It does not contain source code for any of the runtime components.

sci-ndp/rexec/              # this repo — docs, helm, examples
├── helm/
│   └── rexec/              # umbrella Helm chart
│       ├── Chart.yaml
│       ├── values.yaml.template
│       ├── scidx-rexec-broker/
│       ├── scidx-rexec-server-deploy-api/
│       └── ndp-ep-api/
├── user/
│   ├── ndp-ep-rexec.ipynb  # NDP EP + rexec example
│   └── direct-rexec-lib.ipynb
├── reference/
│   ├── svg/                # architecture diagrams
│   └── legacy-doc/         # manual deploy docs
└── docs/                   # this GitHub Pages site

Dev Prerequisites

Path A — Develop the NDP EP Library (editable)

Use this path when you're working on ndp-ep-py. The scidx-rexec library is pulled in from PyPI as a normal dependency.

1

Clone ndp-ep-py

git clone https://github.com/sci-ndp/ndp-ep-py.git
cd ndp-ep-py
2

Install in editable mode with rexec extra

pip install -e ".[rexec]"

This installs ndp-ep-py from source (editable) and pulls scidx-rexec from PyPI.

Path B — Develop the Rexec Client Library (editable)

Use this path when you're working on SciDx-rexec itself.

1

Clone SciDx-rexec

git clone https://github.com/sci-ndp/SciDx-rexec.git
cd SciDx-rexec
2

Install in editable mode

pip install -e .
3

(Optional) Also install ndp-ep-py in editable mode

If you need to work on both layers simultaneously:

# In a separate directory:
git clone https://github.com/sci-ndp/ndp-ep-py.git
cd ndp-ep-py
pip install -e ".[rexec]"
# pip will use your local editable scidx-rexec since it's already installed

Testing scidx-rexec Directly

When contributing to or debugging SciDx-rexec, you can bypass the NDP Endpoint layer entirely and drive the library directly with remote_func. This is the fastest way to iterate on the client library in isolation.

Prerequisites You need a running broker and deploy API reachable from your machine — either a local kind cluster (see Helm Chart Dev) or a shared dev environment. The notebook direct-rexec-lib.ipynb also demonstrates this pattern.
1

Install your editable build

Follow Path B above to install scidx-rexec in editable mode first.

2

Configure and call remote_func

from rexec.client_api import remote_func

token = "<user-token>"

# Point directly at the broker
remote_func().set_remote_addr("<example.broker.addr>")
remote_func().set_remote_port("5559")
remote_func().set_exec_token(token)

# Point at the deploy API to auto-provision a server pod
remote_func().set_api_url("http://example.deploy.api.addr/rexec/spawn")
remote_func().set_environment("input_requirements.txt", token)

@remote_func
def my_fn():
    import platform
    return platform.node()

result = my_fn()
print(result)
⚠️
Server pod not auto-provisioned via NDP EP When calling remote_func directly, set_environment triggers the deploy API to spawn a server pod on demand. If you skip it, a server pod must already be connected to the broker before your call.

ZeroMQ Protocol

Rexec uses a ROUTER–DEALER ZeroMQ pattern at the broker:

Client (DEALER) ──→ Broker frontend (ROUTER)
                         │
                    [routing table]
                         │
Broker backend (ROUTER) ──→ Server Pod (DEALER)

Server Pod Lifecycle

1

Client requests a server

Client calls the NDP EP API spawn endpoint with their Bearer token. The EP API forwards the request to the Deploy API.

2

Deploy API provisions a pod

Deploy API creates a new namespace (rexec-server-<user-id>) and deploys a rexec-server pod. The pod automatically connects to the broker's internal ClusterIP.

3

Client dispatches jobs

Client sends serialized function calls through the broker. The broker routes them to the user's dedicated server pod.

4

Session ends / cleanup

When the session is complete or times out, the Deploy API tears down the pod and namespace.

Authentication Flow

Client                   NDP EP API              AUTH_API_URL
  │                          │                         │
  │── GET /api/rexec/spawn ──▶│                         │
  │   Authorization: Bearer  │── GET <AUTH_API_URL> ──▶│
  │                          │   Authorization: Bearer  │
  │                          │◀── {username, groups} ───│
  │                          │                         │
  │      (if ACL enabled)    │
  │                          │── check groups ──▶ [allow/deny]
  │                          │
  │◀── {broker_url, ...} ────│
  │                          │
  │── ZMQ DEALER connect ──▶ [Broker]
  │   token in handshake     │── validate token ──▶ AUTH_API_URL

Contributing Guidelines

Before opening a PR
  • Open an issue to discuss the change first for non-trivial features
  • Fork the relevant repo and create a feature branch from main
  • Ensure tests pass and add tests for new behaviour
  • Keep PRs focused — one feature/fix per PR

Client Library and Server Repos

For scidx-rexec (client library) and the rexec server repo, follow the standard PR process — open a pull request against main, and a rexec admin will review and merge accordingly. PyPI releases for the client library are managed exclusively by the rexec admin team; contributors do not need to handle publishing.

Docker Image CI: Broker and Server Deploy API

The broker and server-deploy-api repos each have a GitHub Actions workflow that fires on every merge to main. It builds the Docker image and pushes it to Docker Hub under the latest tag automatically.

Helm chart always pulls the latest image The chart sets imagePullPolicy: Always for both components, so a running cluster will pick up the new latest image on the next pod restart or rolling update; thus, no subchart version bump needed.

Commit Style

Follow Conventional Commits:

feat: add async job dispatch to rexec client
fix: handle ZMQ timeout on broker disconnect
docs: add deploy API auth flow diagram
chore: bump scidx-rexec dependency to 0.2.0

Release Process (Helm Chart)

The Helm chart is released automatically via the release-charts.yaml GitHub Actions workflow using helm/chart-releaser-action.

1

Bump the chart version

Edit helm/rexec/Chart.yaml and increment version (semver).

# helm/rexec/Chart.yaml
version: 0.1.2    # ← increment this
appVersion: "0.1.0"
2

Push to main

The workflow triggers on any push to main that changes files under helm/**.

git add helm/rexec/Chart.yaml
git commit -m "chore: bump chart to 0.1.2"
git push origin main
3

chart-releaser publishes automatically

The action packages the chart as a .tgz, creates a GitHub Release, and updates index.yaml on the gh-pages branch. GitHub Pages serves the Helm repo index from there.

Local Helm Chart Development

# Update subcharts
helm dependency update ./helm/rexec

# Lint
helm lint ./helm/rexec

# Template render (dry-run)
helm template rexec ./helm/rexec \
  -f ./helm/rexec/values.yaml \
  --debug

# Install to a local cluster (e.g., kind or minikube)
helm upgrade --install rexec ./helm/rexec \
  -f ./helm/rexec/values.yaml \
  -n rexec --create-namespace
kind cluster for local testing
kind create cluster --name rexec-dev
kubectl config use-context kind-rexec-dev
helm upgrade --install rexec ./helm/rexec -f ./helm/rexec/values.yaml -n rexec --create-namespace