Skip to content

feat(schedule): add Temporal schedule for periodic scanning#4

Open
revied wants to merge 7 commits intoblock:mainfrom
revied:feature/temporal-schedule
Open

feat(schedule): add Temporal schedule for periodic scanning#4
revied wants to merge 7 commits intoblock:mainfrom
revied:feature/temporal-schedule

Conversation

@revied
Copy link
Copy Markdown
Contributor

@revied revied commented Apr 10, 2026

Summary

  • Adds Temporal Schedule API support so the OrchestratorWorkflow runs automatically on a configurable cron (default: daily at 06:00 UTC per the design doc)
  • Schedule manager uses a create-or-update pattern to handle server restarts gracefully (if schedule already exists, updates it if cron changed)
  • Disabled by default via SCHEDULE_ENABLED=false for backwards compatibility

Configuration

Env Var Default Purpose
SCHEDULE_ENABLED false Opt-in to scheduled scanning
SCHEDULE_CRON 0 6 * * * Cron expression (daily at 06:00 UTC)
SCHEDULE_ID version-guard-scan Stable schedule ID for idempotent restarts
SCHEDULE_JITTER 5m Random jitter to prevent thundering herd

Changes

New:

  • pkg/schedule/schedule.go - Schedule manager with create-or-update logic
  • pkg/schedule/schedule_test.go - 6 unit tests covering all paths

Modified:

  • cmd/server/main.go - Config fields, schedule wiring with graceful failure
  • pkg/workflow/orchestrator/workflow.go - ScanID fallback from workflow execution ID for scheduled runs

Test plan

  • go build ./... compiles
  • go test ./pkg/schedule/... - 6/6 tests pass
  • go test ./... - full suite passes
  • Manual: SCHEDULE_ENABLED=true go run ./cmd/server/ with local Temporal dev server

🤖 Generated with Claude Code

Adds Temporal Schedule API support so the OrchestratorWorkflow runs
automatically on a configurable cron (default: every 6 hours). The
schedule manager uses a create-or-update pattern to handle restarts
gracefully. Disabled by default via SCHEDULE_ENABLED=false.

New files:
- pkg/schedule/schedule.go: Schedule manager with create-or-update logic
- pkg/schedule/schedule_test.go: 6 unit tests covering all paths

Modified:
- cmd/server/main.go: Added SCHEDULE_ENABLED, SCHEDULE_CRON,
  SCHEDULE_ID, SCHEDULE_JITTER config; wiring with graceful failure
- pkg/workflow/orchestrator/workflow.go: ScanID fallback from workflow
  execution ID for scheduled runs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@revied revied requested a review from bakayolo as a code owner April 10, 2026 13:42
Aligns with the design doc which specifies daily at 06:00 UTC,
not every 6 hours.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bakayolo
Copy link
Copy Markdown
Collaborator

🤖 Automated Expert Review

Summary

Adds Temporal Schedule API support for periodic orchestrator scanning with a solid create-or-update pattern. Well-structured code with good test coverage, but has a potential nil pointer panic in the update path and missing startup timeout.


Findings

🚫 BLOCKER: Nil pointer dereference in DoUpdate closure

File: pkg/schedule/schedule.go:97-103
The DoUpdate closure directly accesses input.Description.Schedule.Spec.CronExpressions without nil-checking Spec. While the outer code (line 86) handles nil existingSpec, the Temporal SDK provides a fresh ScheduleUpdateInput inside DoUpdate — if that input has a nil Spec, this will panic and crash the server on startup.
Suggestion: Add a nil guard inside the closure:

if input.Description.Schedule.Spec == nil {
    input.Description.Schedule.Spec = &client.ScheduleSpec{}
}

⚠️ WARNING: Schedule update only propagates Spec, not Action

File: pkg/schedule/schedule.go:97-103
When updating an existing schedule, only the CronExpressions and Jitter are overwritten. If someone changes the TaskQueue via config, the existing schedule will continue firing with the old task queue/timeout settings.
Suggestion: Also update the action in DoUpdate:

if action, ok := input.Description.Schedule.Action.(*client.ScheduleWorkflowAction); ok {
    action.TaskQueue = cfg.TaskQueue
}

⚠️ WARNING: No timeout on EnsureSchedule during startup

File: cmd/server/main.go:352-358
EnsureSchedule makes multiple RPCs to Temporal (Create, Describe, Update). Using the base context.Background() means this can block startup indefinitely if Temporal is unresponsive.
Suggestion: Wrap with a timeout:

schedCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
schedErr := scheduleMgr.EnsureSchedule(schedCtx, ...)

ℹ️ INFO: Missing test for nil Spec edge case

File: pkg/schedule/schedule_test.go
All test mocks populate Spec in describeOut. Adding a TestEnsureSchedule_AlreadyExists_NilSpec case would have caught the nil pointer issue above.

ℹ️ INFO: Nice ScanID fallback pattern

File: pkg/workflow/orchestrator/workflow.go:56-60
Using workflow.GetInfo(ctx).WorkflowExecution.ID as fallback ScanID for scheduled runs is deterministic and replay-safe — great choice. 👍


Checklist

Check Status Notes
🔒 Security No secrets, credentials, or injection vectors
🏗️ Reliability ⚠️ Nil pointer risk in DoUpdate; missing startup timeout
🚀 Staging before Prod N/A Feature flag gated (SCHEDULE_ENABLED=false default)
📦 Atlantis Plan N/A Not an infrastructure PR
🧪 Tests ⚠️ 6 tests cover happy paths well; missing nil Spec edge case
⚙️ CI Checks 🚫 "Test" check is failing (1m49s)
💰 Cost/Blast Radius Disabled by default, low risk

Verdict: REQUEST CHANGES

The BLOCKER (nil pointer panic in DoUpdate) must be fixed before merge. The CI test failure also needs investigation. The two WARNINGs (partial update propagation, missing startup timeout) should ideally be addressed but are not strictly blocking.


🤖 Review by Amp agent · not a substitute for human review

revied and others added 5 commits April 13, 2026 09:30
- Add nil guard for Spec in DoUpdate closure to prevent panic
- Propagate TaskQueue changes in schedule updates via Action assertion
- Add 10s timeout on EnsureSchedule during startup
- Add TestEnsureSchedule_AlreadyExists_NilSpec test case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename ScheduleConfig -> Config, ScheduleCreator -> Creator (revive)
- Reorder mockScheduleHandle fields for alignment (govet)
- Add nolint for hugeParam on mock Create (matches SDK interface)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Handle

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 13, 2026

Codecov Report

❌ Patch coverage is 55.95238% with 37 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cmd/server/main.go 0.00% 29 Missing ⚠️
pkg/schedule/schedule.go 88.67% 4 Missing and 2 partials ⚠️
pkg/workflow/orchestrator/workflow.go 0.00% 2 Missing ⚠️
Files with missing lines Coverage Δ
pkg/workflow/orchestrator/workflow.go 0.00% <0.00%> (ø)
pkg/schedule/schedule.go 88.67% <88.67%> (ø)
cmd/server/main.go 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants