Skip to main content

component-tasks

Renders CronJobs, worker Deployments, and manual jobs for an app. All three share the parent app's image, pull secret, and envFrom secret via the global: block.

When to use it

  • Cron: run a command on a schedule (./craft up, ./craft cleanup, …).
  • Worker: long-running process that consumes a queue (./craft queue:work).
  • Manual: one-off command you trigger by hand (migrations, backfills, cache warm). Rendered as a suspended CronJob so it never auto-fires.

Syntax

component-tasks:
cron:
- name: heartbeat
schedule: "* * * * *"
command: ["./craft", "up"]
- name: nightly-cleanup
schedule: "0 3 * * *"
command: ["./craft", "cleanup"]
resources:
requests:
cpu: 50m
memory: 64Mi
workers:
- name: queue-default
command: ["./craft", "queue:work"]
replicas: 2
- name: queue-emails
command: ["./craft", "queue:work", "emails"]
replicas: 1
manual:
- name: db-migrate
command: ["./craft", "migrate"]
- name: cache-warm
command: ["./craft", "cache:warm"]
  • Empty lists (the default) produce no resources.
  • Generated names: <global.nameOverride>-cron-<name>, <global.nameOverride>-worker-<name>, and <global.nameOverride>-manual-<name>.

Cron fields

FieldRequiredDefaultNotes
nameyesUsed in resource name + labels
scheduleyesStandard cron expression
commandyesContainer command (array form)
concurrencyPolicynoForbidSkip new run if previous still running
successfulJobsHistoryLimitno3
failedJobsHistoryLimitno1
startingDeadlineSecondsnoDrop jobs that miss their slot by this much
backoffLimitnoRetries before the Job is failed
activeDeadlineSecondsnoHard timeout for the Job
restartPolicynoOnFailurePod restart policy
imagenoparent{ repository, tag, pullPolicy } per-task override
resourcesnoStandard resource requests/limits

Worker fields

FieldRequiredDefaultNotes
nameyes
commandyes
replicasno1
terminationGracePeriodSecondsno30
imagenoparentPer-worker override
resourcesno
livenessProbenoRaw probe spec (e.g. exec: { command: [...] })

Manual fields

Same shape as cron, minus schedule and startingDeadlineSeconds.

FieldRequiredDefaultNotes
nameyesUsed in resource name + labels
commandyesContainer command (array form)
concurrencyPolicynoForbid
successfulJobsHistoryLimitno3
failedJobsHistoryLimitno1
backoffLimitnoRetries before the Job is failed
activeDeadlineSecondsnoHard timeout for the Job
restartPolicynoOnFailurePod restart policy
imagenoparentPer-task override
resourcesno

Triggering a manual job

The rendered CronJob has suspend: true and a placeholder schedule (0 0 31 2 * — Feb 31, never fires). Run it on demand with:

kubectl create job <app>-manual-<name>-$(date +%s) \
--from=cronjob/<app>-manual-<name> \
-n <namespace>

Example:

kubectl create job myapp-manual-db-migrate-$(date +%s) \
--from=cronjob/myapp-manual-db-migrate \
-n myapp-staging

Generated resources

Each cron entry → one batch/v1 CronJob. Each worker entry → one apps/v1 Deployment with restartPolicy: Always. Each manual entry → one suspended batch/v1 CronJob. All inherit image and pull secret from global.image / global.imagePullSecrets, with envFrom pointing at global.secretName.

Labels and the app Service

Cron pods are labelled app: <global.nameOverride>, task: cron, task-name: <name>; worker pods the same with task: worker; manual job pods the same with task: manual. They share the app label with the main workload but intentionally lack the component: web label, so the app's Service — which selects app and component: web (see App charts → Service and pod labels) — never sends HTTP traffic to a queue worker, cron, or manual pod.