This demo shows that two different actor templates running two different binaries
can share a single WorkerPool — even when the templates live in different atespaces.
Each template gates on the pool via workerSelector, a label selector matched
against the pool's labels — pool selection is cluster-wide, not scoped by atespace
or namespace.
- A k8s cluster with Agent Substrate installed (
./hack/install-ate.sh --deploy-ate-system). koinstalled for building images.- A GCS bucket for storing snapshots (configured via
BUCKET_NAMEenv var).
Note
Do not manually edit the demos/multi-template/*.yaml.tmpl manifests. The
installation script automatically injects your ${BUCKET_NAME} environment
variable during deployment.
./hack/install-ate.sh --deploy-demo-multi-templateThis command will:
- Build the
counterandfspersistimages usingko. - Create one
WorkerPool(shared-pool) in theate-demo-multi-template-poolnamespace (multi-template.yaml.tmpl). - Create 2 atespaces —
ate-demo-multi-template-counterandate-demo-multi-template-fspersist— and an actor template in each:counter(counter-template.yaml.tmpl) andfspersist(fspersist-template.yaml.tmpl), both selecting the pool via the sameworkerSelectorlabel and applied withkubectl ate create actor-template. - Wait until both templates' golden snapshots are built.
Each actor goes in its template's atespace — --template names the template,
resolved in the actor's atespace — and their DNS names embed that atespace:
# Install the CLI as a kubectl plugin if not already installed
go install ./cmd/kubectl-ate
# Create two actors from different templates, one per atespace.
kubectl ate create actor c1 -a ate-demo-multi-template-counter --template counter
kubectl ate create actor f1 -a ate-demo-multi-template-fspersist --template fspersistTo interact with the router locally:
kubectl port-forward -n ate-system svc/atenet-router 8000:80When you send an HTTP request through the router, Substrate automatically detects the session, activates (resumes) the actor onto an available worker pod, and proxies the traffic. The two headers form the complete routing key: the Actor name alone is not enough, so each request below pairs it with the Atespace where that Actor was created.
# counter binary
curl -s -H "ate-target-actor: ate-demo-multi-template-counter/c1" http://localhost:8000
# -> hello from: <ip> | preserved memory count: 1
# fspersist binary
curl -s -H "ate-target-actor: ate-demo-multi-template-fspersist/f1" http://localhost:8000
# -> pod: <ip>
# --- history ---
# pod=<ip> | count=0 | time=<timestamp>Confirm both actors landed on workers in the one shared-pool:
kubectl ate get workersThe counter increments its in-memory count on each request, while fspersist prepends
a line to its history file on each request. Suspending and re-requesting an actor
preserves that state across the snapshot/restore cycle:
kubectl ate suspend actor f1 -a ate-demo-multi-template-fspersist
curl -s -H "ate-target-actor: ate-demo-multi-template-fspersist/f1" http://localhost:8000 # history persists; count keeps climbingRemove the demo — this deletes the actors (suspending running ones first), the templates, both atespaces, and then the pool and its namespace:
./hack/install-ate.sh --delete-demo-multi-template