#23924·harbor

fix(jobservice): CPU spin when cron expression can never fire

Author: nikitakodkanyCreated Sep 14, 2026Updated Sep 14, 2026

Description

Cron expressions that are syntactically valid but can never fire (e.g. `0 0 3 30 2 *` - Feb 30) cause jobservice to spin and saturate CPU.

robfig/cron validates each field individually against its allowed range, so day-of-month=30 and month=2 both pass Parse(). However schedule.Next() returns time.Time{} since no matching date exists within the five-year search window.

Root cause

Three compounding failures:

  1. ValidateCronString accepts the expression - Parse() succeeds, no error is returned.
  2. scheduleNextJobs loops indefinitely - time.Time{}.Before(horizon) is always true (year 1 < any real time), and each iteration overwrites the same Redis key via HMSET, saturating CPU.
  3. clearDirtyJobs cannot clean up the poisoned scheduled-queue entry - it queries ZRANGEBYSCORE with a lower bound of 0, but the zero-time job has score -62135596800 (negative), so it is never found.

Expected behavior

  • ValidateCronString should reject cron expressions that can never fire.
  • The scheduleNextJobs loop should exit cleanly when Next() returns zero time.
  • clearDirtyJobs should clean up entries with negative epoch scores.

Steps to reproduce

Configure a Harbor GC schedule with cron 0 0 3 30 2 * via PUT /api/v2.0/system/gc/schedule. Observe jobservice CPU spike to near-limit.