✦ For everyone, free.

Practical knowledge for real and everyday life

Home

Kubernetes CronJob History Management

Kubernetes CronJob History Management retains past job runs, enabling visibility, troubleshooting, and auditing in Kubernetes environments.

Kubernetes CronJob History Management is the set of retention controls that determine how many completed and failed Job objects a batch/v1 CronJob keeps around after execution, governed primarily by the .spec.successfulJobsHistoryLimit and .spec.failedJobsHistoryLimit fields. Because every scheduled tick produces a new Job object, a CronJob left running indefinitely without any bound on retained history would accumulate an ever-growing number of stale objects in etcd, degrading kubectl get performance and cluttering namespace listings without providing proportionally useful debugging value.

History management strikes a deliberate balance: keep enough recent runs available for operators to inspect logs and outcomes after something goes wrong, while automatically pruning older runs once they no longer offer meaningful debugging value relative to the storage and clutter cost of keeping them.


The History Limit Fields

successfulJobsHistoryLimit

Defaults to 3 if unset. Caps the number of Jobs retained that completed with the Complete condition. Once a new successful Job pushes the count of retained successful Jobs above this limit, the CronJob controller deletes the oldest excess successful Jobs (and their Pods, via cascading deletion).

failedJobsHistoryLimit

Defaults to 1 if unset. Caps the number of Jobs retained that reached the Failed condition, pruned the same way — oldest excess failed Jobs are deleted first.

spec:
  successfulJobsHistoryLimit: 5
  failedJobsHistoryLimit: 3

Setting a Limit of Zero

Setting either limit to 0 disables retention of that outcome type entirely — every successful (or failed) Job is deleted essentially immediately after completion. This is sometimes used for extremely high-frequency CronJobs where even a handful of retained Jobs represents meaningful object churn, at the cost of having no in-cluster history at all to inspect after the fact.


Interaction with ttlSecondsAfterFinished

History limits and ttlSecondsAfterFinished (set on the job template, not the CronJob itself) are independent, complementary mechanisms rather than alternatives to each other:

  • History limits bound retention by count — "keep at most N successful and M failed Jobs," regardless of how much time has passed.
  • ttlSecondsAfterFinished bounds retention by time — "delete this Job N seconds after it finished," regardless of how many other Jobs exist.

A CronJob configured with both will have whichever bound is reached first actually trigger deletion for any given Job — a burst of runs in quick succession will be pruned primarily by the count-based history limit, while a single Job sitting untouched for a long time (on a CronJob that runs infrequently) will eventually be pruned by TTL even if the history-limit count was never exceeded.

spec:
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      ttlSecondsAfterFinished: 604800

Operational Considerations

Choosing Limits Based on Investigation Windows

Failed-job history limits, in particular, should be sized around how quickly failures are typically noticed and investigated. A CronJob monitored actively by an on-call rotation can use a small failedJobsHistoryLimit (1-2), since failures are expected to be triaged promptly; a CronJob with looser monitoring benefits from a larger limit, giving more buffer before a string of consecutive failures overwrites the evidence of an earlier one.

History Is Not a Substitute for External Logging

Because both history limits and TTL eventually delete Job objects — and with them, the ability to run kubectl logs against their Pods — any CronJob whose failure diagnostics matter long-term should ship logs to an external aggregation system rather than relying on in-cluster history retention as a durable audit trail. In-cluster history is best understood as a short-term debugging convenience, not a permanent record.

Auditing Current History Settings Across a Fleet

kubectl get cronjobs -o custom-columns=NAME:.metadata.name,SUCCESS_LIMIT:.spec.successfulJobsHistoryLimit,FAIL_LIMIT:.spec.failedJobsHistoryLimit

Reviewing this across all CronJobs in a namespace or cluster is a useful periodic check to catch CronJobs still relying on defaults that may not suit their actual failure-investigation needs, particularly after a CronJob's schedule frequency changes.


Example

apiVersion: batch/v1
kind: CronJob
metadata:
  name: codartium-history-example
spec:
  schedule: "0 */6 * * *"
  successfulJobsHistoryLimit: 4
  failedJobsHistoryLimit: 5
  jobTemplate:
    spec:
      ttlSecondsAfterFinished: 259200
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: sync
              image: codartium/sync-worker:latest