A Golang job scheduling library that lets you run Go functions at pre-determined intervals using cron expressions, fixed durations, daily, weekly, monthly, or one-time schedules with support for distributed deployments.
Guide to running gocron across multiple instances.
Gocron supports two distributed patterns:
Simple pattern where one instance becomes leader and schedules all jobs.
s, _ := gocron.NewScheduler(
gocron.WithDistributedElector(myElector),
)
// Only leader schedules jobs
j, _ := s.NewJob(
gocron.DurationJob(time.Minute),
gocron.NewTask(doWork),
)
s.Start()Characteristics:
Detailed guide: Leader Election
Per-job locking pattern where all instances schedule but only one executes each job.
s, _ := gocron.NewScheduler(
gocron.WithDistributedLocker(myLocker),
)
// All instances schedule, one executes
j, _ := s.NewJob(
gocron.DurationJob(time.Minute),
gocron.NewTask(doWork),
)
s.Start()Characteristics:
Detailed guide: Distributed Locking
| Factor | Leader Election | Distributed Locking |
|---|---|---|
| Complexity | Low | Medium |
| Load distribution | Single instance | All instances |
| Failover | Instance-level | Job-level |
| Coordination | Once (leader) | Per job execution |
| Use when | Simple deployments | Load distribution needed |
type Elector interface {
IsLeader(context.Context) error
}Return nil if instance is leader, error otherwise.
type Locker interface {
Lock(context.Context, string) (Lock, error)
}
type Lock interface {
Unlock(context.Context) error
}Acquire/release locks per job.
Distributed instances should have synchronized clocks for consistent scheduling.
Detailed guide: Clock Synchronization
Test distributed behavior in development environments.
Detailed guide: Testing Distributed
type redisElector struct {
client *redis.Client
key string
id string
}
func (e *redisElector) IsLeader(ctx context.Context) error {
ok, err := e.client.SetNX(ctx, e.key, e.id, 10*time.Second).Result()
if err != nil {
return err
}
if !ok {
return errors.New("not leader")
}
return nil
}type redisLocker struct {
client *redis.Client
}
func (l *redisLocker) Lock(ctx context.Context, key string) (gocron.Lock, error) {
ok, err := l.client.SetNX(ctx, key, "1", time.Minute).Result()
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("lock held")
}
return &redisLock{client: l.client, key: key}, nil
}Install with Tessl CLI
npx tessl i tessl/golang-github-com-go-co-op-gocron-v2@2.19.1docs
api
examples
guides