fix: warn on misleading cron step values#1948
Conversation
Standard cron step syntax `*/N` means "values where value % N == 0", not "every N units". For example, `*/33` in the minute field fires at :00 and :33 only, not every 33 minutes. This confuses users who expect interval semantics. Add checkMisleadingStepValues() that detects step values that don't evenly divide their field range (60 for minutes, 24 for hours) and attaches warning strings to the Schedule struct. The warning explains which values the schedule actually fires at and lists valid divisors. The schedule still executes normally -- warnings are informational. Fixes dagucloud#639
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe changes add diagnostic warnings to cron schedule expressions with misleading step values (like Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
internal/core/schedule.go (1)
332-344: Special-case for*/5in hour field is reasonable but consider documenting the rationale.The exception for
*/5in the hour field (which fires at 0, 5, 10, 15, 20 — not evenly distributed across 24 hours) is a pragmatic choice to reduce noise for a commonly-used pattern.Consider whether similar exceptions might be useful for other common patterns (e.g.,
*/45in minutes fires at 0, 45 which is often intentional for "twice per hour"). This could be addressed in a follow-up if users report false-positive warnings.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/core/schedule.go` around lines 332 - 344, The isExpectedStepValue function currently special-cases step==5 for the "hour" field; update this code to include a clear inline comment documenting the rationale (that "*/5" in hours is a common intentional pattern and results in uneven final interval at day boundaries) and reference that similar special-cases could be added later (e.g., minute steps like 45) if users report false positives; make the comment adjacent to the existing if block for fieldName == "hour" && step == 5 so future maintainers know why this exception exists and where to extend it.internal/core/schedule_test.go (1)
61-67: Test only validates first warning; consider checking all warnings for multi-field expressions.When an expression triggers warnings for both minute and hour fields (e.g.,
*/7 */7 * * *), onlywarnings[0]is validated. This is fine for current test cases since each tests a single field, but consider adding a test case that verifies both fields generate warnings independently.💡 Example additional test case
{ name: "both minute and hour step 7 warns", expr: "*/7 */7 * * *", wantWarning: true, contains: []string{"minute field"}, // or validate both warnings },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/core/schedule_test.go` around lines 61 - 67, The test only asserts on warnings[0], so add coverage that validates all returned warnings for multi-field expressions: update the test in internal/core/schedule_test.go that calls checkMisleadingStepValues (the tt loop) to either add a new case for "*/7 */7 * * *" (wantWarning true) or change the assertions to iterate over warnings and ensure each expected substring in tt.contains appears in some warning (e.g., check that for each s in tt.contains there exists an entry in warnings containing s) rather than only checking warnings[0]; reference the checkMisleadingStepValues call and the warnings variable when implementing this broadened validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/core/dag.go`:
- Around line 741-742: core.Schedule now carries Warnings (populated by
checkMisleadingStepValues and serialized in MarshalJSON) but the API layer drops
them; update the API surface by adding a "warnings" property to the Schedule
schema in api/v1/api.yaml, regenerate the API client/server code so api.Schedule
gains a Warnings field, and modify the transformer function toSchedule() to copy
core.Schedule.Warnings into api.Schedule.Warnings so warnings are returned to
API consumers (or explicitly document if you intend warnings to remain
internal).
In `@internal/core/schedule.go`:
- Around line 315-326: The formatted warning's arguments are misordered causing
the unit and the list of times to appear in the wrong places; update the
fmt.Sprintf call that builds warnings (using expr, field, rule.fieldName,
firesAt, rule.unit, step, rule.base, divisors) so the arguments match the format
string: pass expr, field, rule.fieldName, strings.Join(firesAt, ", "),
rule.unit, step, rule.unit, rule.base, strings.Join(divisors, ", ") to
fmt.Sprintf in that order (ensure you reference the existing variables used in
this function: expr, field, rule.fieldName, firesAt, rule.unit, step, rule.base,
divisors).
---
Nitpick comments:
In `@internal/core/schedule_test.go`:
- Around line 61-67: The test only asserts on warnings[0], so add coverage that
validates all returned warnings for multi-field expressions: update the test in
internal/core/schedule_test.go that calls checkMisleadingStepValues (the tt
loop) to either add a new case for "*/7 */7 * * *" (wantWarning true) or change
the assertions to iterate over warnings and ensure each expected substring in
tt.contains appears in some warning (e.g., check that for each s in tt.contains
there exists an entry in warnings containing s) rather than only checking
warnings[0]; reference the checkMisleadingStepValues call and the warnings
variable when implementing this broadened validation.
In `@internal/core/schedule.go`:
- Around line 332-344: The isExpectedStepValue function currently special-cases
step==5 for the "hour" field; update this code to include a clear inline comment
documenting the rationale (that "*/5" in hours is a common intentional pattern
and results in uneven final interval at day boundaries) and reference that
similar special-cases could be added later (e.g., minute steps like 45) if users
report false positives; make the comment adjacent to the existing if block for
fieldName == "hour" && step == 5 so future maintainers know why this exception
exists and where to extend it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: cf78d7c3-c600-48fd-b2ff-65b2f7f5f573
📒 Files selected for processing (3)
internal/core/dag.gointernal/core/schedule.gointernal/core/schedule_test.go
- Fix fmt.Sprintf argument order in warning message (unit and firesAt were swapped, producing "fires at minutes 0, 33" instead of "fires at 0, 33 minutes") - Surface schedule warnings through BuildWarnings so they appear in DAG validation output alongside other build warnings
|
@tmchow Thank you for the nice PR! Could you run |
Done! |
yottahmd
left a comment
There was a problem hiding this comment.
LGTM ! Thanks for making cron schedule debugging easier!
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1948 +/- ##
==========================================
- Coverage 68.62% 68.09% -0.54%
==========================================
Files 468 475 +7
Lines 59992 61368 +1376
==========================================
+ Hits 41171 41787 +616
- Misses 14959 15618 +659
- Partials 3862 3963 +101
... and 45 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
|
Thanks for the review! |
Summary
Adds warnings for cron step values that don't evenly divide their field range, like
*/33in the minute field. These are valid cron but confuse users who expect interval semantics.Why this matters
Users in #639 report that
*/33 * * * *doesn't run "every 33 minutes" as they expect. Standard cron*/Nmeans "values where value % N == 0", so*/33fires at :00 and :33 only. The same issue applies to*/7,*/13, and any step that doesn't divide 60 (minutes) or 24 (hours).Changes
internal/core/dag.go: AddedWarnings []stringfield toSchedulestructinternal/core/schedule.go: AddedcheckMisleadingStepValues()that detects non-divisor steps in minute and hour fields. Called fromNewCronSchedule()and attached to the returnedSchedule. Warning text explains which values actually fire and lists valid divisors.internal/core/schedule_test.go: Tests covering*/33,*/7(should warn),*/5,*/15(should not warn), and hour field variants.The schedule still executes normally. Warnings are informational only.
Testing
go test ./internal/core/...passes. 6 test cases cover the warning detection for both minute and hour fields.Fixes #639
This contribution was developed with AI assistance (Codex).
Summary by CodeRabbit