Workflow orchestration (Temporal)
Temporal is a durable workflow engine. You write ordinary functions, and Temporal makes sure they run to completion even when the process crashes, the network drops, or a step needs to wait hours for an external event. It handles retries, timeouts, state, and history automatically.
Peach hosts a Temporal service per codops. Your code connects to it with a
per-codops API key, TEMPORAL_API_KEY.
| gRPC (external) | temporal-grpc.<codops>.peach.ebu.io:443 |
| gRPC (in-cluster) | peach-codops-<codops>-temporal-frontend:7233 |
| Web UI | https://temporal.<codops>.peach.ebu.io |
| Default namespace | default (7-day history retention) |
Replace <codops> with your codops name.
Not yet on your codops? Use the test environment in the meantime
If your codops is not yet enabled for Temporal, you can start building and testing against the shared test environment on dev-2 while your deployment is being set up.
| gRPC | temporal-grpc.test.dev.peach.ebu.io:443 |
| Web UI | https://temporal.test.dev.peach.ebu.io |
| API key | test:<token> — ask the Peach team for the test token |
| Namespace | default |
When you move to your own codops, only two things change in your code:
- The hostname:
test.dev.peach.ebu.io→<your-codops>.peach.ebu.io - The API key prefix:
test:<token>→<your-codops>:<token>
Everything else — SDK calls, namespace, TLS setup — stays identical.
Authentication
The gRPC endpoint takes a {codops}:{token} bearer credential. The token is
TEMPORAL_API_KEY, a key in your codops'
secret store, so tasks and endpoints already have it as an
environment variable. It is separate from your peach-models token: rotating one
does not break the other. If you need it outside the cluster, ask the Peach team.
Your api_key is then <codops>:<token>.
In-cluster code can skip the public endpoint, TLS, and the credential entirely by connecting to the internal service name. Most Temporal workloads should run this way.
Connect — Python
import os
from temporalio.client import Client
# External (from outside the cluster, or from another cluster)
client = await Client.connect(
"temporal-grpc.<codops>.peach.ebu.io:443",
namespace="default",
api_key=os.environ["TEMPORAL_API_KEY"], # "<codops>:<token>"
tls=True,
)
# In-cluster — no TLS, no key
client = await Client.connect(
"peach-codops-<codops>-temporal-frontend:7233",
namespace="default",
)
Install the SDK:
# pyproject.toml
dependencies = ["temporalio"]
Connect — Go
import (
"crypto/tls"
"os"
"go.temporal.io/sdk/client"
)
// External
c, err := client.Dial(client.Options{
HostPort: "temporal-grpc.<codops>.peach.ebu.io:443",
Namespace: "default",
Credentials: client.NewAPIKeyStaticCredentials(os.Getenv("TEMPORAL_API_KEY")),
ConnectionOptions: client.ConnectionOptions{
TLS: &tls.Config{},
},
})
// In-cluster — no TLS, no key
c, err := client.Dial(client.Options{
HostPort: "peach-codops-<codops>-temporal-frontend:7233",
Namespace: "default",
})
Web UI
https://temporal.<codops>.peach.ebu.io is protected by GitLab OAuth (same
login as the rest of Peach). The Temporal Web UI has no authentication of its
own, so the OAuth session is the only gate — anyone who can log in can read
every workflow history and terminate running workflows. Treat it as a privileged
surface.
Things worth knowing
- Namespace
defaultkeeps histories for 7 days. Older runs are permanently gone. Need a different retention or a dedicated namespace? Ask the platform team. - The datastore is shared with Prefect on the same codops. Heavy load from either service affects the other.
- The credential is per-codops, not per-user. Rotating it breaks every
caller at the same time. Load it from the
TEMPORAL_API_KEYenvironment variable rather than hardcoding it. - In-cluster workers need no public credential. A pod running inside the
cluster connects directly to
peach-codops-<codops>-temporal-frontend:7233with no API key.
Related
- Large models (peach-models) — the same
{codops}:{token}format, with a different token. - Event Driven Pipelines — for lighter, message- driven work that does not need durable state.
- Secret handler — how to store and load credentials in your codops.