Skip to main content

Cron Jobs

VEF exposes github.com/coldsmirk/vef-framework-go/cron as a typed wrapper around gocron. The framework DI module provides cron.Scheduler automatically; applications that need custom wiring can pass their own gocron.Scheduler to cron.NewScheduler.

Public Surface

The package has no exported fields. Its public top-level API is:

APIContract
cron.Schedulerhigh-level scheduler interface used by DI, custom handlers, and modules
cron.NewScheduler(scheduler gocron.Scheduler) cron.Schedulerwraps a caller-provided gocron.Scheduler; the caller must pass a usable scheduler
cron.Jobinterface returned by Scheduler.NewJob, Scheduler.Jobs, and Scheduler.Update
cron.JobDefinitioninterface accepted by Scheduler.NewJob and Scheduler.Update
cron.JobDescriptorOptionoption type accepted by all built-in job-definition constructors
cron.OneTimeJobDefinitionone-time job definition returned by NewOneTimeJob
cron.DurationJobDefinitionfixed-interval job definition returned by NewDurationJob
cron.DurationRandomJobDefinitionrandom-interval job definition returned by NewDurationRandomJob
cron.CronJobDefinitioncron-expression job definition returned by NewCronJob
cron.NewOneTimeJob(times []time.Time, options ...cron.JobDescriptorOption) *cron.OneTimeJobDefinitionruns immediately when times is nil/empty, once at one time, or once at each supplied time
cron.NewDurationJob(interval time.Duration, options ...cron.JobDescriptorOption) *cron.DurationJobDefinitionrepeats at a fixed duration interval
cron.NewDurationRandomJob(minInterval time.Duration, maxInterval time.Duration, options ...cron.JobDescriptorOption) *cron.DurationRandomJobDefinitionrepeats with a random interval between minInterval and maxInterval
cron.NewCronJob(expression string, withSeconds bool, options ...cron.JobDescriptorOption) *cron.CronJobDefinitionuses a cron expression; withSeconds=true expects the seconds field, false uses the standard 5-field form
cron.WithName(name string)sets the required human-readable job name
cron.WithTags(tags ...string)assigns tags used by RemoveByTags and Job.Tags
cron.WithConcurrent()allows overlapping executions of the same job; without it, jobs use singleton wait mode
cron.WithStartAt(startAt time.Time)starts the schedule at a specific time; this takes precedence over WithStartImmediately
cron.WithStartImmediately()starts the schedule immediately when no WithStartAt time is set
cron.WithStopAt(stopAt time.Time)stops the schedule at a specific time
cron.WithLimitedRuns(limitedRuns uint)applies a run limit only when limitedRuns > 0
cron.WithContext(ctx context.Context)forwards a non-nil context to the underlying job option for cancellation support
cron.WithTask(handler any, params ...any)sets the required function handler and forwards params to it through gocron.NewTask
cron.ErrJobNameRequiredjob options were built without a name
cron.ErrJobTaskHandlerRequiredtask build found a nil handler
cron.ErrJobTaskHandlerMustFunctask build found a non-function handler

cron.Scheduler

The public scheduler interface includes:

MethodSignatureContract
JobsJobs() []cron.Jobreturns the jobs currently registered with the wrapped scheduler
NewJobNewJob(definition cron.JobDefinition) (cron.Job, error)builds the definition, registers it, and returns a cron.Job; validation errors from the definition are returned before registration
RemoveByTagsRemoveByTags(tags ...string)removes all jobs that have any of the supplied tags
RemoveJobRemoveJob(id string) errorparses id as a UUID and removes that job; invalid non-UUID strings return a parse error before delegation
StartStart()starts scheduling and execution; jobs added after start are scheduled by the wrapped scheduler
StopJobsStopJobs() errorstops job execution without removing definitions; jobs can run again after Start()
UpdateUpdate(id string, definition cron.JobDefinition) (cron.Job, error)parses id as a UUID, builds the replacement definition, and preserves the job identifier
JobsWaitingInQueueJobsWaitingInQueue() intreturns the wrapped scheduler's waiting queue count; it is meaningful when wait mode is in use

Use IDs returned by Job.ID() for RemoveJob and Update. Arbitrary strings are not accepted.

cron.Job

Each registered job can be inspected or triggered through:

MethodSignatureContract
IDID() stringreturns the underlying UUID as a string
LastRunLastRun() (time.Time, error)returns the last run start time
NameName() stringreturns the configured job name
NextRunNextRun() (time.Time, error)returns the next scheduled run time
NextRunsNextRuns(count int) ([]time.Time, error)returns count future scheduled run times
RunNowRunNow() errortriggers an immediate execution while respecting job/scheduler limits and run limits
TagsTags() []stringreturns the configured tag list

Job Definitions

cron.JobDefinition is the common interface accepted by Scheduler.NewJob(...) and Scheduler.Update(...). The four exported definition structs are returned by their constructors; callers usually do not instantiate them directly because their scheduling fields are internal.

ConstructorSchedule
cron.NewOneTimeJob(nil, options...) or cron.NewOneTimeJob([]time.Time{}, options...)one immediate run
cron.NewOneTimeJob([]time.Time{t}, options...)one run at t
cron.NewOneTimeJob([]time.Time{a, b}, options...)one run at each supplied time
cron.NewDurationJob(interval, options...)fixed interval
cron.NewDurationRandomJob(minInterval, maxInterval, options...)random interval in the supplied range
cron.NewCronJob(expression, true, options...)cron expression with seconds
cron.NewCronJob(expression, false, options...)standard 5-field cron expression

All built-in definitions first build the task and then build job options. That means a nil or non-function task handler takes precedence over a missing name if both are invalid.

Job Options

Every constructor accepts JobDescriptorOption values:

OptionBehavior
cron.WithName(name)required; without it NewJob/Update return an error wrapping ErrJobNameRequired
cron.WithTask(handler, params...)required; handler must be a function; params are forwarded to gocron.NewTask(handler, params...)
cron.WithTags(tags...)stores tags for listing and RemoveByTags
cron.WithConcurrent()disables the default singleton wait mode for this job
cron.WithStartAt(startAt)sets a start date/time and wins over WithStartImmediately when both are present
cron.WithStartImmediately()applies only when WithStartAt did not set a non-zero time
cron.WithStopAt(stopAt)adds a stop date/time only when stopAt is non-zero
cron.WithLimitedRuns(limitedRuns)adds a run limit only when limitedRuns > 0
cron.WithContext(ctx)adds the context option only when ctx is non-nil; handlers that accept context.Context can observe cancellation

By default, a job cannot overlap with another execution of itself. The package adds singleton wait mode unless WithConcurrent() is supplied.

Error Sentinels

ErrorTrigger
cron.ErrJobTaskHandlerRequiredWithTask was not supplied or received nil
cron.ErrJobTaskHandlerMustFuncWithTask received a non-function handler
cron.ErrJobNameRequiredtask build succeeded, but WithName was missing or empty

These sentinels are wrapped by the build path, for example failed to build job task: ... or failed to build job options: .... Use errors.Is(err, cron.ErrJobNameRequired) and the other sentinels instead of direct equality.

DI Scheduler Defaults

When the framework creates the scheduler through its DI module, the observable defaults are:

DefaultMeaning
local time zoneschedules use time.Local
stop timeout 30sgraceful shutdown window
scheduler logger and monitorjob scheduling and completion are logged
concurrent job limit 1000 with wait modeexcess executions wait in the queue instead of being dropped
lifecycle start/shutdownapp start calls scheduler start; app stop shuts the scheduler down

These defaults apply to the framework-provided scheduler. A scheduler passed to cron.NewScheduler uses whatever options the caller configured.

Minimal Example

package jobs

import (
"context"
"time"

"github.com/coldsmirk/vef-framework-go/cron"
)

func RegisterCleanupJob(scheduler cron.Scheduler) error {
_, err := scheduler.NewJob(
cron.NewDurationJob(
10*time.Minute,
cron.WithName("cleanup-expired-sessions"),
cron.WithTask(func(ctx context.Context) error {
return nil
}),
),
)

return err
}

Practical Usage

Use cron when you need application-owned background work such as:

  • periodic cleanup
  • polling and sync tasks
  • scheduled aggregation
  • retry or timeout scanning

If the task is domain-heavy, keep business logic in a service and use the scheduler only for orchestration.

Next Step

Read Transactions if scheduled work needs explicit database transaction control.