cronengine

package module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 6, 2026 License: MIT Imports: 7 Imported by: 0

README

radobaan-cron-engine

Distributed cron scheduling with Redis-backed locking. Wraps robfig/cron with seconds support and provides a lightweight lock per usecase/target so concurrent workers don’t double-execute the same job.

Installation

  • Go 1.22+
  • Redis running and reachable
go get github.com/bimonugraraga/radobaan-cron-engine

Quick Start

This snippet mirrors the example in main.go.

package main

import (
    "context"
    "log"
    "time"
    cronengine "github.com/bimonugraraga/radobaan-cron-engine"
    "github.com/redis/go-redis/v9"
)

func main() {
    ctx := context.Background()

    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })
    if err := rdb.Ping(ctx).Err(); err != nil {
        log.Fatal("redis not running:", err)
    }
    scheduler := cronengine.NewScheduler(rdb)

    scheduler.Schedule(cronengine.SchedulerRequest{
        Ctx:         ctx,
        Spec:        "* * * * * *",
        WithLock:    true,
        AutoRelease: false,
        Usecase:     "runUsecase",
        Target:      "0",
        TTL:         5 * time.Second,
        Func: func() {
            // your job here
        },
    })
}

Parameters

  • Spec: Cron expression with seconds enabled (six fields). Example * * * * * * runs every second.
  • WithLock: Enable distributed locking; if false, schedules without lock.
  • AutoRelease: When true, releases the lock after job finishes; when false, rely on TTL expiration.
  • Usecase: Logical name grouping locks (Preferably Function Name) (e.g., send_email).
  • Target: Dimension to lock within the usecase (Which specific resource that job operates on) (e.g., user ID, date key).
  • TTL: Lock expiration; prevents indefinite lock if a worker dies.
  • Func: The function to execute on schedule.

Example Usecase Target: send_email (Usecase) and 2024-01-01 or user:123 (Target)

Lock-Only Example

Use the locking mechanism independently of cron to guard critical sections across workers.

package main

import (
    "context"
    "log"
    "time"
    cronengine "github.com/bimonugraraga/radobaan-cron-engine"
    "github.com/redis/go-redis/v9"
)

func main() {
    ctx := context.Background()

    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })
    if err := rdb.Ping(ctx).Err(); err != nil {
        log.Fatal(err)
    }

    lock := cronengine.NewLock(rdb)

    ok, err := lock.Acquire(cronengine.LockRequest{
        Ctx: ctx,
        Req: cronengine.Request{
            Usecase: "send_email",
            Target:  "user:123",
            TTL:     10 * time.Second,
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    if !ok {
        log.Println("locked, skip")
        return
    }
    defer lock.Release(cronengine.LockRequest{
        Ctx: ctx,
        Req: cronengine.Request{
            Usecase: "send_email",
            Target:  "user:123",
        },
    })

    // protected work
}

Code References

  • Example: main.go
  • API types: request.go
  • Scheduler: scheduler.go
  • Locking: lock.go

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AcquireScript = redis.NewScript(`
local prev = redis.call("SETBIT", KEYS[1], ARGV[1], 1)

if prev == 1 then
    return 0
end

if tonumber(ARGV[2]) > 0 then
    local ttl = redis.call("TTL", KEYS[1])
    if ttl < 0 then
        redis.call("EXPIRE", KEYS[1], ARGV[2])
    end
end

return 1
`)

Functions

This section is empty.

Types

type Lock

type Lock struct {
	Client *redis.Client
}

func NewLock

func NewLock(rdb *redis.Client) *Lock

func (*Lock) Acquire

func (l *Lock) Acquire(params LockRequest) (bool, error)

func (*Lock) Release

func (l *Lock) Release(params LockRequest) error

type LockRequest

type LockRequest struct {
	Ctx context.Context
	Req Request
}

type Request

type Request struct {
	Usecase string        // Unique identifier for the usecase (example: "send_email")
	Target  string        // Target resource or entity to lock (example: "user:123", "2026-03-04")
	TTL     time.Duration // Time-to-live for the lock in seconds (default: 60)
}

Lock Request

type Scheduler

type Scheduler struct {
	Client *redis.Client
}

func NewScheduler

func NewScheduler(rdb *redis.Client) *Scheduler

func (*Scheduler) Schedule

func (s *Scheduler) Schedule(params SchedulerRequest) error

type SchedulerRequest

type SchedulerRequest struct {
	Ctx         context.Context
	Spec        string
	WithLock    bool
	AutoRelease bool
	Usecase     string
	Target      string
	TTL         time.Duration
	Func        func()
}

Cron Request

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL