Source Repositories
The Rexec ecosystem is spread across four GitHub repositories. Each has a distinct responsibility:
| Repo | Role | Language | Link |
|---|---|---|---|
| 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
- Python 3.9+ (3.11 recommended)
git- A ZeroMQ-capable environment (standard on macOS/Linux)
- Docker + Docker Compose (for broker / deploy API local runs)
- Access to a Kubernetes cluster (optional, for end-to-end testing)
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.
Clone ndp-ep-py
git clone https://github.com/sci-ndp/ndp-ep-py.git
cd ndp-ep-py
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.
Clone SciDx-rexec
git clone https://github.com/sci-ndp/SciDx-rexec.git
cd SciDx-rexec
Install in editable mode
pip install -e .
(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.
kind cluster (see Helm Chart Dev) or
a shared dev environment. The notebook
direct-rexec-lib.ipynb
also demonstrates this pattern.
Install your editable build
Follow Path B above to install scidx-rexec in editable mode first.
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)
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)
- Clients connect to the external NodePort (
30001) as DEALER sockets - Server pods connect to the internal ClusterIP (
5560) as DEALER sockets - The broker is stateless — it forwards frames based on identity routing
- Authentication is validated at the connection handshake via token
Server Pod Lifecycle
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.
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.
Client dispatches jobs
Client sends serialized function calls through the broker. The broker routes them to the user's dedicated server pod.
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
- 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.
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.
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"
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
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 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
Remote Execution
GitHub ↗