Skip to content

Commit 6b483e5

Browse files
committed
Added /scale subresource to TemporalWorkerDeployment CRD
- Enables KEDA and Kubernetes HPA to directly scale the custom resource - Controller aggregates replica counts in status.replicas - Controller sets label selector in status.selector for pod discovery - CRD properly configured with /scale subresource - Tested with 1000-workflow load test demonstrating successful scaling
1 parent ba42a56 commit 6b483e5

File tree

4 files changed

+53
-5
lines changed

4 files changed

+53
-5
lines changed

api/v1alpha1/worker_types.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,17 @@ type TemporalWorkerDeploymentStatus struct {
108108
// so it's generally not a good idea to read from the status of the root object.
109109
// Instead, you should reconstruct it every run.
110110

111+
// Replicas is the total number of non-terminated pods targeted by this TemporalWorkerDeployment.
112+
// This is used by the /scale subresource to report current replica count to HPA/KEDA.
113+
// +optional
114+
Replicas int32 `json:"replicas,omitempty"`
115+
116+
// Selector is the label selector for pods managed by this TemporalWorkerDeployment.
117+
// This is used by the /scale subresource to allow HPA/KEDA to discover pods.
118+
// Format: "app.kubernetes.io/name=<name>"
119+
// +optional
120+
Selector string `json:"selector,omitempty"`
121+
111122
// TargetVersion is the desired next version. If TargetVersion.Deployment is nil,
112123
// then the controller should create it. If not nil, the controller should
113124
// wait for it to become healthy and then move it to the CurrentVersion.
@@ -348,7 +359,9 @@ type ManualRolloutStrategy struct{}
348359

349360
//+kubebuilder:object:root=true
350361
//+kubebuilder:subresource:status
362+
//+kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
351363
// +kubebuilder:resource:shortName=twd;twdeployment;tworkerdeployment
364+
//+kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".status.replicas",description="Current replicas"
352365
//+kubebuilder:printcolumn:name="Current",type="string",JSONPath=".status.currentVersion.buildID",description="Current build ID"
353366
//+kubebuilder:printcolumn:name="Target",type="string",JSONPath=".status.targetVersion.buildID",description="Target build ID"
354367
//+kubebuilder:printcolumn:name="Ramp %",type="number",JSONPath=".status.targetVersion.rampPercentage",description="Ramp percentage"

helm/temporal-worker-controller/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ apiVersion: v2
22
name: temporal-worker-controller
33
description: A Helm chart for the Temporal Worker Controller
44
type: application
5-
version: 0.11.0
6-
appVersion: 1.1.1
5+
version: 0.10.0
6+
appVersion: 1.1.0

helm/temporal-worker-controller/crds/temporal.io_temporalworkerdeployments.yaml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ spec:
1919
scope: Namespaced
2020
versions:
2121
- additionalPrinterColumns:
22+
- description: Current replicas
23+
jsonPath: .status.replicas
24+
name: Replicas
25+
type: integer
2226
- description: Current build ID
2327
jsonPath: .status.currentVersion.buildID
2428
name: Current
@@ -64,7 +68,6 @@ spec:
6468
gate:
6569
properties:
6670
input:
67-
type: object
6871
x-kubernetes-preserve-unknown-fields: true
6972
inputFrom:
7073
properties:
@@ -73,25 +76,27 @@ spec:
7376
key:
7477
type: string
7578
name:
79+
default: ""
7680
type: string
7781
optional:
7882
type: boolean
7983
required:
8084
- key
81-
- name
8285
type: object
86+
x-kubernetes-map-type: atomic
8387
secretKeyRef:
8488
properties:
8589
key:
8690
type: string
8791
name:
92+
default: ""
8893
type: string
8994
optional:
9095
type: boolean
9196
required:
9297
- key
93-
- name
9498
type: object
99+
x-kubernetes-map-type: atomic
95100
type: object
96101
workflowType:
97102
type: string
@@ -4057,6 +4062,11 @@ spec:
40574062
type: array
40584063
lastModifierIdentity:
40594064
type: string
4065+
replicas:
4066+
format: int32
4067+
type: integer
4068+
selector:
4069+
type: string
40604070
targetVersion:
40614071
properties:
40624072
buildID:
@@ -4141,4 +4151,8 @@ spec:
41414151
served: true
41424152
storage: true
41434153
subresources:
4154+
scale:
4155+
labelSelectorPath: .status.selector
4156+
specReplicasPath: .spec.replicas
4157+
statusReplicasPath: .status.replicas
41444158
status: {}

internal/controller/state_mapper.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package controller
66

77
import (
8+
"strings"
9+
810
"github.com/temporalio/temporal-worker-controller/api/v1alpha1"
911
"github.com/temporalio/temporal-worker-controller/internal/k8s"
1012
"github.com/temporalio/temporal-worker-controller/internal/temporal"
@@ -35,6 +37,25 @@ func (m *stateMapper) mapToStatus(targetBuildID string) *v1alpha1.TemporalWorker
3537

3638
status.LastModifierIdentity = m.temporalState.LastModifierIdentity
3739

40+
// Compute total replicas from all managed deployments for /scale subresource
41+
// This allows HPA/KEDA to query the current replica count
42+
var totalReplicas int32
43+
for _, deployment := range m.k8sState.Deployments {
44+
if deployment.Status.Replicas > 0 {
45+
totalReplicas += deployment.Status.Replicas
46+
}
47+
}
48+
status.Replicas = totalReplicas
49+
50+
// Set label selector for /scale subresource - allows HPA/KEDA to discover pods
51+
// Uses app.kubernetes.io/name label since all managed pods share this label
52+
// Note: workerDeploymentName is namespace/name, but we only want the name part for labels
53+
name := m.workerDeploymentName
54+
if idx := strings.LastIndex(name, "/"); idx >= 0 {
55+
name = name[idx+1:]
56+
}
57+
status.Selector = "app.kubernetes.io/name=" + name
58+
3859
// Get build IDs directly from temporal state
3960
currentBuildID := m.temporalState.CurrentBuildID
4061
rampingBuildID := m.temporalState.RampingBuildID

0 commit comments

Comments
 (0)