A gocron locker implementation using gorm
go get github.com/go-co-op/gocron-gorm-lock/v2Here is an example usage that would be deployed in multiple instances
package main
import (
"fmt"
"github.com/go-co-op/gocron/v2"
gormlock "github.com/go-co-op/gocron-gorm-lock/v2"
"gorm.io/gorm"
"time"
)
func main() {
var db * gorm.DB // gorm db connection
var worker string // name of this instance to be used to know which instance run the job
// db.AutoMigrate(&gormlock.CronJobLock{}) // We need the table to store the job execution
locker, err := gormlock.NewGormLocker(db, worker)
// handle the error
s, err := gocron.NewScheduler(gocron.WithDistributedLocker(locker))
// handle the error
f := func() {
// task to do
fmt.Println("call 1s")
}
_, err = s.NewJob(gocron.DurationJob(1*time.Second), gocron.NewTask(f), gocron.WithName("unique_name"))
if err != nil {
// handle the error
}
s.Start()
}To check a real use case example, check examples.
- The table
cron_job_locksneeds to exist in the database. One possible option is to usedb.Automigrate(&gormlock.CronJobLock{}) - In order to uniquely identify the job, the locker uses the unique combination of
job name + timestamp(by default with precision to seconds). Check JobIdentifier for more info.
JobIdentifier is how the locker identify when the job was run.
Gorm Lock tries to lock the run of a job by uniquely identify a particular execution of a job with the combination of
- job name
- job identifier
There is a unique key constraint in those two columns. The default implementation to uniquely identify a particular execution of job is using the following combination:
jobName: retrieved from the cron job.jobIdentifier: a timestamp of when the job run.
For more details check gorm-lock-options.go.
Example
Imagine that you have two instances running (i1 and i2).
And you configure a cron job (named myJob) to run at a certain period (e.g. every minute).
At t1, i1 is faster in picking up the job, and then this happened:
i1creates a record in the database, (jobName: test, jobIdentifier: t1).- Then,
i2will try to lock and insert a record with the same values (jobName: test, jobIdentifier: t1). - But there is a combined unique constraint in the columns
jobNameandjobIdentifiermakingi2not able to run the job.
By default, the timestamp precision is in seconds, meaning that if a job named myJob is executed at 2025-01-01 10:11:12 15:16:17.000, the resulting job identifier will be the combination of myJob and 2025-01-01 10:11:12.
- It is possible to change the precision with
WithDefaultJobIdentifier(newPrecision), e.g.WithDefaultJobIdentifier(time.Hour) - It is also possible to completely override the way the job identifier is created with the
WithJobIdentifier()option.
To see these two options in action, check the test TestJobReturningExceptionWhenUnique
Gorm Lock also removes old entries stored in gormlock.CronJobLock. You can configure the time interval, and the time to live with the following options:
WithTTLWithCleanInterval