Skip to content

JobSnooze ignores Config.Test.Time when calculating scheduled_at #1322

Description

@pablobaldez

Description

Config.Test.Time was introduced in #754 (following #751) to let tests provide a synthetic rivertype.TimeGenerator. Scheduled-job eligibility uses that configured time source, but JobSnooze calculates its next absolute timestamp from the process wall clock:

nextAttemptScheduledAt := time.Now().Add(snoozeErr.Duration)

The executor then compares that wall-clock-derived timestamp with e.Time.Now(). When Config.Test.Time is intentionally ahead of or behind wall time, the two values belong to different timelines.

This is present in v0.39.0 and still appears on master.

Example

Assume:

  • process wall clock: 2026-07-22 12:00 UTC
  • Config.Test.Time: 2026-06-10 12:00 UTC
  • worker returns river.JobSnooze(8 * time.Hour)

The current implementation stores approximately:

scheduled_at = 2026-07-22 20:00 UTC

The expected synthetic-time value is:

scheduled_at = 2026-06-10 20:00 UTC

Advancing the synthetic clock by eight hours therefore does not make the job eligible; it remains scheduled until the wall-clock-derived timestamp. If the synthetic clock is ahead of wall time, the inverse can happen and the snoozed job may become immediately eligible.

This makes Config.Test.Time unreliable for behavioral or manual simulation tests that exercise workers which repeatedly snooze themselves.

Suggested change

Use the executor's configured time generator when calculating the snooze target:

- nextAttemptScheduledAt := time.Now().Add(snoozeErr.Duration)
+ nextAttemptScheduledAt := e.Time.Now().Add(snoozeErr.Duration)

This is also consistent with the comparison immediately below, which already uses e.Time.Now().

When Config.Test.Time is nil, River's default time generator still delegates to time.Now(), so ordinary runtime behavior should remain unchanged.

Suggested regression test

Create a client/worker with Config.Test.Time fixed to an instant that differs materially from wall time, return JobSnooze(duration), and assert that the resulting job's ScheduledAt equals the synthetic instant plus the snooze duration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions