cronjob

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2022 License: MIT Imports: 6 Imported by: 0

README

CronJob build Go Report Card

CronJob is like cron but uses golang time specification.

go get it:
go get github.com/Lambels/cronjob@latest

Code Examples

Scheduling functions.

Its very simple, the cronjob object has AddFunc method exposed, you use this to add your function to the scheduler. AddFunc takes 3 parameters respectively: FuncJob, Schedule, ...JobConf. You can schedule functions before or after starting the processing thread.

FuncJob:

Job1 and Job2 implement the type FuncJob

func Job1() error {
    fmt.Println("Hello World, im a FuncJob")
    return nil
}

func Job2() error {
    fmt.Println("Hello World, im also a FuncJob")
    return fmt.Errorf("ERR")
}
Schedules:

Schedules determine the time at which your FunJob runs at.

package main

func main() {
    // runs in 5 seconds
    sched1 := cronjob.In(time.Now(), 5 * time.Second)

    // runs in 1 second
    sched2 := cronjob.In(time.Now(), 4 * time.Microsecond)

    // runs on 2022, 03, 16 at 16:18:59
    sched3 := cronjob.At(time.Date(
        2022,
        time.March,
        26,
        16,
        18,
        59,
        0,
        time.Local, // use cronjob location.
    ))

    // runs every hour.
    sched4 := cronjob.Every(1 * time.Hour)

    // runs on each 3 hour intervals: 03:00, 06:00, 09:00, 12:00, 15:00, 18:00, 21:00, 24:00
    sched5 := cronjob.EveryFixed(3 * time.Hour)
}
JobConf:

Job Configurations configure the behaviour of the job. Examples of such functions are found here.

A job configuration is a function with the signature JobConf func(*Job).

func Job1() error {
    fmt.Println("Hello World, im a FuncJob")
    return nil
}

func Job2() error {
    fmt.Println("Im a FuncJob which returns an error")
    return fmt.Errorf("ERR")
}

func main() {
    cron := cronjob.New()

    cron.AddFunc(
        Job1,
        cronjob.In(cron.Now(), 5 * time.Second),
        

        // configs:
        cronjob.WithRunOnStart(), // runs job on start.
    )

    cron.AddFunc(
        Job2,
        cronjob.In(cron.Now(), 10 * time.Second),

        // configs:
        cronjob.WithChain(
            // retry Job2 5 times in 5 second intervals.
            // always add cornjob.Retry() the first in the chain.
            cronjob.NewChain(cronjob.Retry(5 * time.Second, 5)),
        ),
    )
}
All together:
func Job1() error {
    fmt.Println("Hello World, im a FuncJob")
    return nil
}

func Job2() error {
    fmt.Println("Hello World, im also a FuncJob")
    return fmt.Errorf("ERR")
}

func main() {
    cron := cronjob.New()

    cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second), cronjob.WithRunOnStart())

    cron.Start()

    cron.AddFunc(Job2, cronjob.EveryFixed(cron.Now(), 1 * time.Hour))

    time.Sleep(1 * time.Hour)

    cron.Close()
}

Chains:

Chains allow you to customize the behavour of the Jobs when the jobs are running. A chain function making up a chain has the following signature: func(FuncJob) FuncJob. A chain is just a slice of these functions: type Chain []func(FuncJob) FuncJob.

cronjob.Retry() should always be added first in the chain to keep expected behaviour.

Inspiration from cron

Creating A Chain:
func SomeChain(fj cronjob.FuncJob) cronjob.FuncJob {
	return func() error {
		log.Println("Hello from SomeChain")
        return fj() // call next function in chain.
	}
}

func SomeOtherChain(fj cronjob.FuncJob) cronjob.FuncJob {
	return func() error {
		log.Println("Hello from SomeOtherChain")
        return fj() // call next function in chain.
	}
}

func Job() error {
    log.Println("Hello from Job")
    return nil
}

func main() {
    chain := cronjob.NewChain(SomeChain, SomeOtherChain)
    chain.Run(job)

    // output:
    // "Hello from SomeChain"
    // "Hello from SomeOtherChain"
    // "Hello from Job"
}
Merging n Chains:
func SomeChain(fj cronjob.FuncJob) cronjob.FuncJob {
	return func() error {
		log.Println("Hello from SomeChain")
        return fj() // call next function in chain.
	}
}

func SomeOtherChain(fj cronjob.FuncJob) cronjob.FuncJob {
	return func() error {
		log.Println("Hello from SomeOtherChain")
        return fj() // call next function in chain.
	}
}

func SomeOtherOtherChain(fj cronjob.FuncJob) cronjob.FuncJob {
	return func() error {
		log.Println("Hello from SomeOtherOtherChain")
        return fj() // call next function in chain.
	}
}

func Job() error {
    log.Println("Hello from Job")
    return nil
}

func main() {
    chain1 := cronjob.NewChain(SomeChain, SomeOtherChain)
    chain2 := cronjob.NewChain(SomeOtherOtherChain)

    chain3 := cronjob.MergeChains(chain1, chain2)
    chain3.Run(Job)

    // output:
    // "Hello from SomeChain"
    // "Hello from SomeOtherChain"
    // "Hello from SomeOtherOtherChain"
    // "Hello from Job"
}
Fault Tolerance:

always add cronjob.Retry() first in the chain!

func SomeChain(fj cronjob.FuncJob) cronjob.FuncJob {
	return func() error {
		log.Println("Hello from SomeChain")
        return fj() // call next function in chain.
	}
}

func Job() error {
    log.Println("Hello from Job")
    return fmt.Errorf("ERR")
}

func main() {
    chain1 := cronjob.NewChain(cronjob.Retry(5*time.Second, 5), SomeChain)

    chain1.Run(Job)

    // output:
    // "Hello from SomeChain"
    // "Hello from Job"
    // "Hello from SomeChain"
    // "Hello from Job"
    // "Hello from SomeChain"
    // "Hello from Job"
    // "Hello from SomeChain"
    // "Hello from Job"
    // "Hello from SomeChain"
    // "Hello from Job"
}

Removing Jobs:

The cronjob object has RemoveJob method exposed, it takes the job id as a parameter. RemoveJob will no-op if no job matches the id. You can call RemoveJob either after starting the processing thread or before.

Get Job ID:
func Job1() error {
    fmt.Println("Hello World, im a FuncJob")
    return nil
}

func main() {
    cron := cronjob.New()

    id := cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))

    // store id ...
}
Remove Job:
func Job1() error {
    fmt.Println("Hello World, im a FuncJob")
    return nil
}

func main() {
    cron := cronjob.New()

    id := cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))

    cron.RemoveJob(id)

    id := cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))

    cron.Start()
    defer cron.Stop()
    
    cron.RemoveJob(id)
}

Stopping:

There are 2 ways to stop a cronjob's processing thread, Stop and StopWithFlush. Stop exits the processing thread and StopWithFlush exits the processing thread and runs the remaining jobs providing a context to wait for their completion.

Stop:
func Job1() error {
    fmt.Println("Hello World, im a FuncJob")
    return nil
}

func main() {
    cron := cronjob.New()

    cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))

    cron.Start()
    cron.Stop()

    cron.AddFunc(Job1, cronjob.In(cron.Now(), 2 * time.Second)) // still works.
}
StopWithFlush:
func Job1() error {
    time.Sleep(1 * time.Hour)
    return nil
}
func Job2() error {
    time.Sleep(5 * time.Second)
    return nil
}

func main() {
    cron := cronjob.New()

    cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))
    cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))

    cron.Start()
    ctx := cron.StopWithFlush()
    <-ctx.Done() // waits for Job1 and Job2 to finish. (1 hour)

    cron.AddFunc(Job1, cronjob.In(cron.Now(), 2 * time.Second)) // still works.
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Retry

func Retry(timeout time.Duration, max int) func(FuncJob) FuncJob

Retry will retry your job decorated with past chains max (field) times with a timeout (field) delay.

Retry MUST only be added first in cronjob.NewChain() if you want all the chains to run properly. Not adding retry as the first argument in NewChain will cause unexpected behaviour.

Types

type Chain

type Chain []func(FuncJob) FuncJob

Chain is a slice of decorator functions.

func MergeChains

func MergeChains(n ...Chain) (merged Chain)

MergeChains merges n (field) chains into 1 parent chain.

func NewChain

func NewChain(c ...func(FuncJob) FuncJob) Chain

NewChain returns a chain of decorators which run in FIFO order.

func (Chain) Run

func (c Chain) Run(job FuncJob)

Run runs job (field) with the chains.

type CronJob

type CronJob struct {
	// contains filtered or unexported fields
}

func New

func New(confs ...CronJobConf) *CronJob

func (*CronJob) AddFunc

func (c *CronJob) AddFunc(cmd FuncJob, schedule Schedule, confs ...JobConf) int

AddFunc adds the function: cmd (field) to the execution cycle.

can be called after starting the execution cycle or before.

(*CronJob).AddFunc(foo, cronjob.In(time.Now(), 4 * time.Hour))

will schedule foo to run in 4 hours from time.Now()

func (*CronJob) Jobs

func (c *CronJob) Jobs() []*Node

Jobs returns the current nodes which are registered to the scheduler.

func (*CronJob) Location

func (c *CronJob) Location() *time.Location

Location returns the location used by the instance.

func (*CronJob) Now

func (c *CronJob) Now() time.Time

Now returns the current time in the location used by the instance.

func (*CronJob) RemoveJob

func (c *CronJob) RemoveJob(id int)

RemoveJob removes the job with id: id (field). (no-op if job not found)

can be called after starting the execution cycle or before.

func (*CronJob) Run

func (c *CronJob) Run()

Start the processing thread.

no-op if already running.

func (*CronJob) Start

func (c *CronJob) Start()

Start the processing thread in its own gorutine.

no-op if already running.

func (*CronJob) Stop

func (c *CronJob) Stop()

Stop stops the cronjobs processing thread.

no-op if not running.

func (*CronJob) StopWithFlush

func (c *CronJob) StopWithFlush() context.Context

StopWithFlush stops the cronjobs processing thread.

runs all the current jobs and cleans the scheduler.

no-op if not running.

type CronJobConf

type CronJobConf func(*CronJob)

CronJobConf represents a function to configure the behaviour of cronjob.

func WithLocation

func WithLocation(loc *time.Location) CronJobConf

WithLocation sets the location used by cronjob.

func WithLogger

func WithLogger(logger *log.Logger) CronJobConf

WithLogger overwrites the default logger.

func WithVerbose

func WithVerbose() CronJobConf

WithVerbose puts cronjob in verbose mode.

type CyclicSchedule

type CyclicSchedule interface {
	// MoveNextAvtivation re-calculates the next time the schedule will be activated
	// at.
	MoveNextAvtivation(time.Time)

	Schedule
}

type FuncJob

type FuncJob func() error

type Job

type Job struct {
	// contains filtered or unexported fields
}

func (*Job) Run

func (j *Job) Run()

Run runs the function provided to job with the chains.

type JobConf

type JobConf func(*Job)

JobConf represents a function to configure the behaviour of a job.

func WithChain

func WithChain(chain Chain) JobConf

WithChain sets the chains to run with the job.

func WithRunOnStart

func WithRunOnStart() JobConf

WithRunOnStart makes the job run on start.

if running: run when added.

if not running: run when cronjob starts.

note: the job will run with any previous configuration provided.

type Node

type Node struct {
	// The id of the node in the storage system.
	Id int

	// The schedule the node is set to be activated on.
	Schedule Schedule

	// The job which needs to be ran.
	Job *Job
	// contains filtered or unexported fields
}

Node represents a node in the storage system.

type Schedule

type Schedule interface {
	// Calculate calculates the duartion till the next activation time.
	Calculate(time.Time) time.Duration
}

func At

func At(at time.Time) Schedule

At returns a schedule that runs at: at (field).

func Every

func Every(every time.Duration) Schedule

Every runs from now: now (field) in constant increments of every (field).

func EveryFixed

func EveryFixed(every time.Duration) Schedule

EveryFixed finds the next time interval: every (field) and runs it at the nearest interval.

example:

cronjob.EveryFixed(time.Hour * 3)

the schedule will find the next 3 hour interval to run at.

possible 3 hour intervals: 03:00, 06:00, 09:00, 12:00, 15:00, 18:00, 21:00, 24:00

func In

func In(now time.Time, offset time.Duration) Schedule

In returns a schedule that runs from now (field) in offset (field).

type Scheduler

type Scheduler interface {
	// NextCycle returns the duration to sleep before next activation cycle.
	NextCycle(time.Time) time.Duration

	// RunNow returns the jobs that need to be ran now and cleans the scheduler.
	RunNow(time.Time) []*Node

	// GetAll returns all the nodes in the scheduler.
	GetAll() []*Node

	// AddNode adds a new node to the scheduler.
	AddNode(time.Time, *Node)

	// RemoveNode removes node with id provided.
	RemoveNode(int)

	// Clean removes the node (field) and re-calculates appropriate nodes.
	Clean(time.Time, []*Node)
}

Jump to

Keyboard shortcuts

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