# Temporal + kmsvc Integration Design ## Vision Use **kmsvc Queue CRDs** as the source of truth for Temporal worker provisioning. When a Queue is created, the Temporal worker operator automatically spawns a corresponding worker Deployment that listens to the queue's task queue. ## Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ Developer: kubectl apply Queue CRD │ │ (queue: orders-fifo, fifo: true, partitions: 6) │ └──────────────────────┬──────────────────────────────────────────┘ │ v ┌─────────────────────────────────────--─┐ │ TemporalWorker Operator (kmsvc-manage)| │ • Watches Queue CRDs │ │ • Detects temporal.io/enabled label │ │ • Creates/scales Deployments │ └──────────────────────────────────────--┘ │ ┌──────────────┴──────────────┐ │ │ v v ┌─────────────────┐ ┌─────────────────┐ │ Temporal Worker │ │ Temporal Worker │ │ Deployment │ ... │ StatefulSet │ │ (Replicas: N) │ │ (DLQ processor) │ └────────┬────────┘ └────────┬────────┘ │ │ └──────────────┬──────────-┘ │ ┌──────v───────-┐ │ Temporal │ │ Frontend │ │ (Task Queues)│ └───────────────┘ ``` ## CRD: TemporalWorker **Namespace:** `temporal` (co-located with Temporal cluster) ```yaml apiVersion: temporal.kmsvc.io/v1 kind: TemporalWorker metadata: name: worker-orders-fifo # derived from Queue name + suffix namespace: temporal ownerReferences: - apiVersion: kmsvc.io/v1 kind: Queue name: orders-fifo # 1:1 reference to source Queue uid: spec: # Source queue (read-only, set by operator) queueRef: name: orders-fifo namespace: sqs # Queue lives in sqs namespace # Temporal task queue name (defaults to Queue name if omitted) taskQueueName: orders-fifo # Temporal sees this task queue # Worker deployment config image: story-crater-backend:latest # must have Temporal SDK initialized imagePullPolicy: IfNotPresent # Replica count (can be overridden per-queue) replicas: 2 # default: 1, autoscale later # Resource constraints resources: requests: cpu: 500m memory: 512Mi limits: cpu: 2000m memory: 2Gi # Pod placement nodeSelector: {} # default: any worker node affinity: {} # optional: custom affinity rules tolerations: [] # Lifecycle hooks (optional) lifecycle: postStartCommand: [] # e.g., ["register-activities.sh"] preStopCommand: [] # e.g., ["drain-in-flight.sh"] status: phase: Ready # Pending | Ready | Failed replicas: 2 readyReplicas: 2 conditions: - type: WorkerDeploymentReady status: "True" lastTransitionTime: "2026-07-10T12:34:56Z" reason: DeploymentReady message: "Worker Deployment worker-orders-fifo is running 2/2 replicas" - type: TemporalTaskQueueRegistered status: "True" lastTransitionTime: "2026-07-10T12:34:56Z" reason: QueueAvailable message: "Task queue 'orders-fifo' is available in Temporal Frontend" ``` ## Implementation Roadmap ### Phase 1 (MVP): Manual TemporalWorker CRD (user creates explicitly) 1. Define `TemporalWorker` CRD in Go + Kubernetes schema 2. Implement controller that watches TemporalWorker objects 3. For each TemporalWorker: - Create a Deployment with the specified image/replicas/resources - Pod template includes: - Environment variables: `TEMPORAL_FRONTEND_ADDRESS`, `TEMPORAL_TASK_QUEUE`, `TEMPORAL_NAMESPACE` - Init container: wait for Temporal Frontend to be ready (DNS check: `temporal-frontend.temporal.svc.cluster.local:7233`) - Set owner reference back to the source Queue (for cleanup on Queue deletion) 4. Create example TemporalWorker CRD (e.g., `k8s/temporal/workers/worker-orders-fifo.yaml`) 5. Deploy via helmfile postsync hook: `kubectl apply -f k8s/temporal/workers/` ### Phase 2 (Future): Auto-provisioning from Queue CRDs 1. Extend kmsvc Queue CRD with optional label: `temporal.io/worker-enabled: "true"` 2. Extend queue-operator to watch Queue CRDs 3. On Queue creation with the label, auto-create a TemporalWorker CRD 4. Auto-derived fields: - `taskQueueName` = Queue name - `image` = default worker image (from configurable CM or env var) - `replicas` = default (e.g., 1, or derived from Queue.spec.partitionsPerShard) ### Phase 3 (Future): Autoscaling 1. Operator samples Queue depth via `kmsvc.io/metrics` endpoints 2. Adjust TemporalWorker replicas based on lag (similar to HPA but custom logic) 3. Min/max replicas configurable per worker ## Integration Points ### 1. Deployment Pod Template (What workers run) The application container must: - Initialize Temporal SDK worker: `go.temporal.io/sdk/worker.New(...)` - Register activity & workflow functions with the worker - Listen on task queue = TemporalWorker.spec.taskQueueName (env var: `TEMPORAL_TASK_QUEUE`) - Connect to Temporal Frontend: `TEMPORAL_FRONTEND_ADDRESS=temporal-frontend.temporal.svc.cluster.local:7233` **Example (story-crater-backend):** ```go package main import ( "fmt" "os" "go.temporal.io/client" "go.temporal.io/sdk/worker" ) func main() { // Read from TemporalWorker env vars frontendAddr := os.Getenv("TEMPORAL_FRONTEND_ADDRESS") // temporal-frontend.temporal:7233 taskQueue := os.Getenv("TEMPORAL_TASK_QUEUE") // orders-fifo namespace := os.Getenv("TEMPORAL_NAMESPACE") // default c, _ := client.Dial(client.Options{ HostPort: frontendAddr, }) defer c.Close() w := worker.New(c, namespace, taskQueue, worker.Options{}) // Register activities & workflows w.RegisterActivity(activities.ProcessOrder) w.RegisterWorkflow(workflows.OrderWorkflow) w.Run(worker.InterruptCh()) // block forever } ``` ### 2. Kubernetes Environment The TemporalWorker controller injects these env vars into the Deployment: - `TEMPORAL_FRONTEND_ADDRESS` = `temporal-frontend.temporal.svc.cluster.local:7233` - `TEMPORAL_NAMESPACE` = `default` (or from TemporalWorker.spec.namespace) - `TEMPORAL_TASK_QUEUE` = TemporalWorker.spec.taskQueueName - Inherited from Pod: `POD_NAME`, `POD_NAMESPACE`, `NODE_NAME` (via `downwardAPI`) ### 3. Temporal Server Expectations No changes needed. Temporal Frontend auto-discovers task queues as workers connect. A worker that connects to task queue `orders-fifo` will: - Show up in Temporal UI under `/namespaces/default/task-queues` - Receive workflows routed to that task queue - Return activity results to the workflow ### 4. DNS & Network - Workers must resolve `temporal-frontend.temporal.svc.cluster.local:7233` (CoreDNS, Kubernetes standard) - Temporal Frontend Service (already exists, type: ClusterIP) - No ingress needed for worker→Temporal communication (cluster-internal) ## Files to Create/Modify ``` kmsvc-manage/ api/ v1/ temporalworker_types.go # CRD schema (Phase 1) controllers/ temporalworker_controller.go # Reconciliation logic (Phase 1) config/ crd/temporal.kmsvc.io_temporalworkers.yaml # CRD definition YAML homelab/ k8s/ temporal/ workers/ worker-orders-fifo.yaml # Example TemporalWorker instance worker-orders-dlq.yaml # DLQ processor (optional) temporal-worker-rbac.yaml # ServiceAccount + RBAC for worker Deployments ``` ## Validation & Testing 1. **Unit tests:** CRD validation, controller reconciliation loops 2. **Integration test (manual):** ```bash # 1. Deploy Temporal cluster (already done) helmfile apply -l name=temporal # 2. Deploy kmsvc queue-operator with TemporalWorker controller helmfile apply -l name=kmsvc-manage # (future Helm chart) # 3. Create a TemporalWorker CRD kubectl apply -f k8s/temporal/workers/worker-orders-fifo.yaml # 4. Verify Deployment was created kubectl get deploy -n temporal kubectl get pods -n temporal -l app=temporal-worker-orders-fifo # 5. Verify worker is visible in Temporal UI curl https://temporal.riotpiao.homelab.com/api/v1/task-queues # 6. Start a workflow targeting the task queue temporal workflow start --task-queue=orders-fifo --type OrderWorkflow # 7. Verify worker executes the workflow kubectl logs -n temporal -f deploy/temporal-worker-orders-fifo ``` ## Rollout Plan 1. **MVP (kmsvc-manage Phase 1):** - Define TemporalWorker CRD + controller - Build CRUD reconciliation (create/update/delete Deployments) - Document example TemporalWorker manifests - User manually creates TemporalWorker CRDs for each queue 2. **Phase 2 (kmsvc-manage Phase 2):** - Extend Queue CRD with `temporal.io/worker-enabled` label - Auto-generate TemporalWorker on Queue creation - User just: `kubectl apply -f queue-orders-fifo.yaml` → worker auto-provisioned 3. **Phase 3 (kmsvc-manage Phase 3):** - Hook into Prometheus metrics (queue depth, lag) - Scale replicas based on workload