<p>In Kubernetes <a href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/" rel="noreferrer">cronjobs</a>, It is stated in the <a href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-job-limitations" rel="noreferrer">limitations section</a> that </p>

<blockquote>
  <p>Jobs may fail to run if the CronJob controller is not running or broken for a span of time from before the start time of the CronJob to start time plus startingDeadlineSeconds, or if the span covers multiple start times and concurrencyPolicy does not allow concurrency.</p>
</blockquote>

<p>What I understand from this is that, If the <code>startingDeadlineSeconds</code> is set to <code>10</code> and the cronjob couldn't start for some reason at its scheduled time, then it can still be attempted to start again as long as those <code>10</code> seconds haven't passed, however, after the <code>10</code> seconds, it for sure won't be started, is this correct?</p>

<p>Also, If I have <code>concurrencyPolicy</code> set to <code>Forbid</code>, does K8s count it as a fail if a cronjob tries to be scheduled, when there is one already running?</p>

Hesham Massoud
<p>After investigating the code base of the <a href="https://github.com/kubernetes/kubernetes" rel="noreferrer">Kubernetes repo</a>, so this is how the CronJob controller works:</p>
<ol>
<li><p>The CronJob controller <a href="https://github.com/kubernetes/kubernetes/blob/392bf0adef478175b9cf0226b02820eb1820f797/pkg/controller/cronjob/cronjob_controller.go#L95-L96" rel="noreferrer">will check the every 10 seconds</a> the list of cronjobs in the given Kubernetes Client.</p>
</li>
<li><p>For every CronJob, it checks how many schedules it missed in the duration from the <code>lastScheduleTime</code> till now. If there are more than <a href="https://github.com/kubernetes/kubernetes/blob/392bf0adef478175b9cf0226b02820eb1820f797/pkg/controller/cronjob/utils.go#L146" rel="noreferrer">100 missed schedules</a>, then it doesn't start the job and records the event:</p>
<p><code>&quot;FailedNeedsStart&quot;, &quot;Cannot determine if job needs to be started. Too many missed start time (&gt; 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.&quot;</code></p>
</li>
</ol>
<p>It is <strong>important</strong> to note, that if the field <code>startingDeadlineSeconds</code> is set (not <code>nil</code>), it will count how many missed jobs occurred from the value of <code>startingDeadlineSeconds</code> till now. For example, if <code>startingDeadlineSeconds</code> = <code>200</code>, It will count how many missed jobs occurred in the last <code>200</code> seconds. The exact implementation of counting how many missed schedules can be found <a href="https://github.com/kubernetes/kubernetes/blob/392bf0adef478175b9cf0226b02820eb1820f797/pkg/controller/cronjob/utils.go#L96" rel="noreferrer">here</a>.</p>
<ol start="3">
<li><p>In case there are not more than a 100 missed schedules from the previous step, the CronJob controller will check if the time <code>now</code> is not after the time of its <code>scheduledTime + startingDeadlineSeconds </code>, i.e. that it's not too late to start the job (passed the deadline). If it wasn't too late, the job will continue to be attempted to be started by the CronJob Controller. However, If it is already too late, then it doesn't start the job and records the event:</p>
<p><code>&quot;Missed starting window for {cronjob name}. Missed scheduled time to start a job {scheduledTime}&quot;</code></p>
</li>
</ol>
<p>It is also <strong>important</strong> to note, that if the field <code>startingDeadlineSeconds</code> is not set, then it means there is no deadline at all. This means the job will be attempted to start by the CronJob controller without checking if it's later or not.</p>
<p>Therefore to answer the questions above:</p>
<p><strong>1. If the startingDeadlineSeconds is set to 10 and the cronjob couldn't start for some reason at its scheduled time, then it can still be attempted to start again as long as those 10 seconds haven't passed, however, after the 10 seconds, it for sure won't be started, is this correct?</strong></p>
<p>The CronJob controller will attempt to start the job and it will be successfully scheduled if the 10 seconds after it's schedule time haven't passed yet. However, if the deadline has passed, it won't be started this run, and it will be counted as a missed schedule in later executions.</p>
<p><strong>2. If I have concurrencyPolicy set to Forbid, does K8s count it as a fail if a cronjob tries to be scheduled, when there is one already running?</strong></p>
<p>Yes, it will be counted as a missed schedule. Since missed schedules are calculated as I stated above in point 2.</p>
