# README
Fx Cron Module
Installation
go get github.com/ankorstore/yokai/fxcron
Features
This module provides the possibility to run internal cron jobs in your application with:
- automatic panic recovery
- configurable cron jobs scheduling and execution options
- configurable logging, tracing and metrics for cron jobs executions
Documentation
Dependencies
This module is intended to be used alongside:
- the fxconfig module
- the fxlog module
- the fxtrace module
- the fxmetrics module
- the fxgenerate module
Loading
To load the module in your Fx application:
package main
import (
"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxcron"
"github.com/ankorstore/yokai/fxgenerate"
"github.com/ankorstore/yokai/fxlog"
"github.com/ankorstore/yokai/fxmetrics"
"github.com/ankorstore/yokai/fxtrace"
"github.com/go-co-op/gocron/v2"
"go.uber.org/fx"
)
func main() {
fx.New(
fxconfig.FxConfigModule, // load the module dependencies
fxlog.FxLogModule,
fxtrace.FxTraceModule,
fxtrace.FxTraceModule,
fxmetrics.FxMetricsModule,
fxgenerate.FxGenerateModule,
fxcron.FxCronModule, // load the module
fx.Invoke(func(scheduler gocron.Scheduler) {
scheduler.Start() // start the cron jobs scheduler
}),
).Run()
}
Configuration
Configuration reference:
# ./configs/config.yaml
app:
name: app
env: dev
version: 0.1.0
debug: true
modules:
log:
level: info
output: stdout
trace:
processor:
type: stdout
cron:
scheduler:
seconds: true # to allow seconds based cron jobs expressions (impact all jobs), disabled by default
concurrency:
limit:
enabled: true # to limit concurrent cron jobs executions, disabled by default
max: 3 # concurrency limit
mode: wait # "wait" or "reschedule"
stop:
timeout: 5s # scheduler shutdown timeout for graceful cron jobs termination, 10 seconds by default
jobs: # common cron jobs options
execution:
start:
immediately: true # to start cron jobs executions immediately (by default)
at: "2023-01-01T14:00:00Z" # or a given date time (RFC3339)
limit:
enabled: true # to limit the number of per cron jobs executions, disabled by default
max: 3 # executions limit
singleton:
enabled: true # to execute the cron jobs in singleton mode, disabled by default
mode: wait # "wait" or "reschedule"
log:
enabled: true # to log cron jobs executions, disabled by default (errors will always be logged).
exclude: # to exclude by name cron jobs from logging
- foo
- bar
metrics:
collect:
enabled: true # to collect cron jobs executions metrics (executions count and duration), disabled by default
namespace: foo # cron jobs metrics namespace (empty by default)
subsystem: bar # cron jobs metrics subsystem (empty by default)
buckets: 1, 1.5, 10, 15, 100 # to define custom cron jobs executions durations metric buckets (in seconds)
trace:
enabled: true # to trace cron jobs executions, disabled by default
exclude: # to exclude by name cron jobs from tracing
- foo
- bar
Notes:
- the cron jobs executions logging will be based on the fxlog module configuration
- the cron jobs executions tracing will be based on the fxtrace module configuration
Check the configuration files documentation for more details.
Cron jobs
Definition
This module provides a simple CronJob interface to implement for your cron jobs:
package cron
import (
"context"
"github.com/ankorstore/yokai/fxcron"
"path/to/service"
)
type SomeCron struct {
service *service.SomeService
}
func NewSomeCron(service *service.SomeService) *SomeCron {
return &SomeCron{
service: service,
}
}
func (c *SomeCron) Name() string {
return "some cron job"
}
func (c *SomeCron) Run(ctx context.Context) error {
// contextual job name and execution id
name, id := fxcron.CtxCronJobName(ctx), fxcron.CtxCronJobExecutionId(ctx)
// contextual tracing
ctx, span := fxcron.CtxTracer(ctx).Start(ctx, "some span")
defer span.End()
// contextual logging
fxcron.CtxLogger(ctx).Info().Msg("some log")
// invoke autowired dependency
err := c.service.DoSomething(ctx, name, id)
// returned errors will automatically be logged
return err
}
Notes:
- your cron job dependencies will be autowired
- you can access from the provided context:
- the cron job name with
CtxCronJobName()
- the cron job execution id with
CtxCronJobExecutionId()
- the tracer with
CtxTracer()
, which will automatically add to your spans theCronJob
name andCronJobExecutionID
attributes - the logger with
CtxLogger()
, which will automatically add to your log records thecronJob
name andcronJobExecutionID
fields
- the cron job name with
Registration
Once ready, you can register and schedule your cron job with AsCronJob()
:
package main
import (
"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxcron"
"github.com/ankorstore/yokai/fxgenerate"
"github.com/ankorstore/yokai/fxlog"
"github.com/ankorstore/yokai/fxmetrics"
"github.com/ankorstore/yokai/fxtrace"
"github.com/go-co-op/gocron/v2"
"go.uber.org/fx"
"path/to/cron"
)
func main() {
fx.New(
fxconfig.FxConfigModule, // load the module dependencies
fxlog.FxLogModule,
fxtrace.FxTraceModule,
fxmetrics.FxMetricsModule,
fxgenerate.FxGenerateModule,
fxcron.FxCronModule, // load the module
fx.Options(
// register, autowire and schedule SomeCron to run every 2 minutes
fxcron.AsCronJob(cron.NewSomeCron, `*/2 * * * *`),
),
).Run()
}
You can override, per job, the common job execution options by providing your own list of gocron.JobOption, for example:
fxcron.AsCronJob(cron.NewSomeCron, `*/2 * * * *`, gocron.WithLimitedRuns(10)),
If you need cron jobs to be scheduled on the seconds level, configure the scheduler
with modules.cron.scheduler.seconds=true
.
It will add seconds
field to the beginning of the scheduling expression, for example to run every 5 seconds:
fxcron.AsCronJob(cron.NewSomeCron, `*/5 * * * * *`),
Note: you can use https://crontab.guru to help you with your scheduling definitions.
Override
By default, the gocron.Scheduler
is created by the DefaultCronSchedulerFactory.
If needed, you can provide your own factory and override the module:
package main
import (
"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxcron"
"github.com/ankorstore/yokai/fxgenerate"
"github.com/ankorstore/yokai/fxlog"
"github.com/ankorstore/yokai/fxmetrics"
"github.com/ankorstore/yokai/fxtrace"
"github.com/go-co-op/gocron/v2"
"go.uber.org/fx"
)
type CustomCronSchedulerFactory struct{}
func NewCustomCronSchedulerFactory() fxcron.CronSchedulerFactory {
return &CustomCronSchedulerFactory{}
}
func (f *CustomCronSchedulerFactory) Create(options ...gocron.SchedulerOption) (gocron.Scheduler, error) {
return gocron.NewScheduler(options...)
}
func main() {
fx.New(
fxconfig.FxConfigModule, // load the module dependencies
fxlog.FxLogModule,
fxtrace.FxTraceModule,
fxmetrics.FxMetricsModule,
fxgenerate.FxGenerateModule,
fxcron.FxCronModule, // load the module
fx.Decorate(NewCustomCronSchedulerFactory), // override the module with a custom factory
fx.Invoke(func(scheduler gocron.Scheduler) { // invoke the cron scheduler
// ...
}),
).Run()
}