How to auto-scale your bot instance on a time-based schedule using KEDA. This lets you run the bot only during business hours and save compute costs overnight and on weekends.
Scale your bot to 1 replica during a configured time window and 0 outside it. Uses KEDA (already installed on the AI cluster).
- Scales the bot Deployment to
desiredReplicasduring the configured window - Outside the window, scales to
minReplicaCount: 0— the pod is completely stopped - No compute costs outside working hours
- KEDA takes ownership of replica count —
BOT_REPLICASin the template becomes the initial value before KEDA kicks in
Add a ScaledObject resource to your deploy/template.yaml, after the NetworkPolicy:
# --- Cron Scaler ---
- apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: ${BOT_NAME}-cron-scaler
labels:
app.kubernetes.io/name: ${BOT_NAME}
app.kubernetes.io/part-of: devbot
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ${BOT_NAME}
minReplicaCount: 0
maxReplicaCount: 1
triggers:
- type: cron
metadata:
timezone: "Europe/Prague"
start: "0 9 * * 1-5"
end: "0 23 * * 1-5"
desiredReplicas: "1"The triggers section is where you define when the bot runs. Each trigger has:
| Field | Description |
|---|---|
timezone |
IANA timezone (e.g. Europe/Prague, America/New_York, US/Eastern) |
start |
Cron expression — when to scale up |
end |
Cron expression — when to scale down |
desiredReplicas |
How many replicas during the window (always "1" for bot instances) |
The cron format is standard 5-field: minute hour day-of-month month day-of-week where day-of-week is 0=Sunday through 6=Saturday.
The framework instance uses this — bot runs 9:00–23:00 Prague time on weekdays:
triggers:
- type: cron
metadata:
timezone: "Europe/Prague"
start: "0 9 * * 1-5"
end: "0 23 * * 1-5"
desiredReplicas: "1"9am–6pm ET, weekdays only:
triggers:
- type: cron
metadata:
timezone: "America/New_York"
start: "0 9 * * 1-5"
end: "0 18 * * 1-5"
desiredReplicas: "1"Run all day Monday through Friday, off Saturday and Sunday:
triggers:
- type: cron
metadata:
timezone: "UTC"
start: "0 0 * * 1"
end: "0 0 * * 6"
desiredReplicas: "1"Bot runs only on Mondays, 8am–5pm:
triggers:
- type: cron
metadata:
timezone: "America/New_York"
start: "0 8 * * 1"
end: "0 17 * * 1"
desiredReplicas: "1"Full hours on weekdays, shorter window on weekends. Use multiple triggers — if any trigger's window is active, the bot scales up:
triggers:
- type: cron
metadata:
timezone: "America/New_York"
start: "0 8 * * 1-5"
end: "0 18 * * 1-5"
desiredReplicas: "1"
- type: cron
metadata:
timezone: "America/New_York"
start: "0 10 * * 0,6"
end: "0 14 * * 0,6"
desiredReplicas: "1"Two separate windows per day:
triggers:
- type: cron
metadata:
timezone: "Europe/Prague"
start: "0 8 * * 1-5"
end: "0 12 * * 1-5"
desiredReplicas: "1"
- type: cron
metadata:
timezone: "Europe/Prague"
start: "0 13 * * 1-5"
end: "0 18 * * 1-5"
desiredReplicas: "1"KEDA evaluates all triggers independently. If any trigger's window is active, the bot scales up. The bot only scales to 0 when no trigger is active. This means triggers are effectively OR'd together — you can combine them to build complex schedules.
KEDA cron triggers use a single IANA timezone per trigger. DST transitions are handled automatically within that timezone — if you set Europe/Prague, the schedule shifts with CET/CEST automatically.
If your team spans multiple timezones, pick the primary one and document the effective hours for others. Different triggers can use different timezones if needed.
Your SaaS file (deploy.yml) must include ScaledObject.keda.sh in managedResourceTypes:
managedResourceTypes:
- Deployment
- NetworkPolicy
- ScaledObject.keda.sh # required for KEDAWithout this, app-interface will prune the ScaledObject on the next sync.
The namespace file (namespaces/*.yml) must also allow it — either managedResourceTypes: [] (allow all, which is the default) or explicitly list ScaledObject.keda.sh.
- Framework instance PR — first implementation
- KEDA cron trigger docs