Categorygithub.com/rizalgowandy/cronx
modulepackage
1.11.0
Repository: https://github.com/rizalgowandy/cronx.git
Documentation: pkg.go.dev

# README

Go Doc Release Go Report Card Build Status Sourcegraph

logo

Cronx is a library to manage cron jobs, a cron manager library. It includes a live monitoring of current schedule and state of active jobs that can be outputted as JSON or HTML template.

Installation

In order to install cronx package, you need to install Go and set your Go workspace first.

You first need Go installed (version >=1.15 is required), then you can use the below Go command to install cronx.

go get -v github.com/rizalgowandy/cronx

Import it in your code:

package main

import "github.com/rizalgowandy/cronx"

Quick Start

Check the example here.

Run docker:

docker-compose up

Run the binary:

make run | jq -R -r '. as $line | try fromjson catch $line'

Then, browse to:

cronx

Available Status

  • Down => Job fails to be registered.
  • Up => Job has just been created.
  • Running => Job is currently running.
  • Success => Job succeeds on the last run, waiting for next run.
  • Error => Job fails on the last run.

Schedule Specification Format

Schedule

Field nameMandatory?Allowed valuesAllowed special characters
SecondsOptional0-59* / , -
MinutesYes0-59* / , -
HoursYes0-23* / , -
Day of monthYes1-31* / , - ?
MonthYes1-12 or JAN-DEC* / , -
Day of weekYes0-6 or SUN-SAT* / , - ?

Predefined schedules

EntryDescriptionEquivalent
@yearly (or @annually)Run once a year, midnight, Jan. 1st0 0 0 1 1 *
@monthlyRun once a month, midnight, first of month0 0 0 1 * *
@weeklyRun once a week, midnight between Sat/Sun0 0 0 * * 0
@daily (or @midnight)Run once a day, midnight0 0 0 * * *
@hourlyRun once an hour, beginning of hour0 0 * * * *

Intervals

@every <duration>

For example, "@every 1h30m10s" would indicate a schedule that activates after 1 hour, 30 minutes, 10 seconds, and then every interval after that.

Please refer to this link for more detail.

Interceptor / Middleware

Interceptor or commonly known as middleware is an operation that commonly executed before any of other operation. This library has the capability to add multiple middlewares that will be executed before or after the real job. It means you can log the running job, send telemetry, or protect the application from going down because of panic by adding middlewares. The idea of a middleware is to be declared once, and be executed on all registered jobs. Hence, reduce the code duplication on each job implementation.

Adding Interceptor / Middleware

package main

import (
	"github.com/rizalgowandy/cronx"
	"github.com/rizalgowandy/cronx/interceptor"
)

func main() {
	// Create cron middleware.
	// The order is important.
	// The first one will be executed first.
	middleware := cronx.Chain(
		interceptor.RequestID,           // Inject request id to context.
		interceptor.Recover(),           // Auto recover from panic.
		interceptor.Logger(),            // Log start and finish process.
		interceptor.DefaultWorkerPool(), // Limit concurrent running job.
	)

	cronx.NewManager(cronx.WithInterceptor(middleware))
}

Check all available interceptors here.

Custom Interceptor / Middleware

package main

import (
	"context"
	"time"

	"github.com/rizalgowandy/cronx"
)

// Sleep is a middleware that sleep a few second after job has been executed.
func Sleep() cronx.Interceptor {
	return func(ctx context.Context, job *cronx.Job, handler cronx.Handler) error {
		err := handler(ctx, job)
		time.Sleep(10 * time.Second)
		return err
	}
}

For more example check here.

FAQ

What are the available commands?

Here the list of commonly used commands.

package main

import (
	"context"

	"github.com/rizalgowandy/cronx"
)

// Schedule sets a job to run at specific time.
// Example:
//  @every 5m
//  0 */10 * * * * => every 10m
func Schedule(spec string, job cronx.JobItf) error

// ScheduleFunc adds a func to the Cron to be run on the given schedule.
func ScheduleFunc(spec, name string, cmd func(ctx context.Context) error) error

// Schedules sets a job to run multiple times at specific time.
// Symbol */,-? should never be used as separator character.
// These symbols are reserved for cron specification.
//
// Example:
//  Spec		: "0 0 1 * * *#0 0 2 * * *#0 0 3 * * *
//  Separator	: "#"
//  This input schedules the job to run 3 times.
func Schedules(spec, separator string, job cronx.JobItf) error

// SchedulesFunc adds a func to the Cron to be run on the given schedules.
func SchedulesFunc(spec, separator, name string, cmd func(ctx context.Context) error) error

Go here to see the list of available commands.

What are the available interceptors?

Go here to see the available interceptors.

Can I use my own router without starting the built-in router?

Yes, you can. This library is very modular.

Here's an example of using gin.

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/rizalgowandy/cronx"
)

func main() {
	// Since we want to create custom HTTP server.
	// Do not forget to shut down the cron gracefully manually here.
	manager := cronx.NewManager()
	defer manager.Stop()

	// An example using gin as the router.
	r := gin.Default()
	r.GET("/custom-path", func(c *gin.Context) {
		c.JSON(http.StatusOK, manager.GetInfo())
	})

	// Start your own server.
	r.Run()
}

Can I still get the built-in template if I use my own router?

Yes, you can.

package main

import (
	"github.com/labstack/echo/v4"
	"github.com/rizalgowandy/cronx"
	"github.com/rizalgowandy/cronx/page"
)

func main() {
	// Since we want to create custom HTTP server.
	// Do not forget to shut down the cron gracefully manually here.
	manager := cronx.NewManager()
	defer manager.Stop()

	// An example using echo as the router.
	e := echo.New()
	index, _ := page.GetStatusTemplate()
	e.GET("/jobs", func(context echo.Context) error {
		// Serve the template to the writer and pass the current status data.
		return index.Execute(context.Response().Writer, manager.GetStatusData(ctx.QueryParam(cronx.QueryParamSort)))
	})
}

Server is located in the US, but my user is in Jakarta, can I change the cron timezone?

Yes, you can. By default, the cron timezone will follow the server location timezone using time.Local. If you placed the server in the US, it will use the US timezone. If you placed the server in the SG, it will use the SG timezone.

package main

import (
	"time"

	"github.com/rizalgowandy/cronx"
)

func main() {
	loc := func() *time.Location { // Change timezone to Jakarta.
		jakarta, err := time.LoadLocation("Asia/Jakarta")
		if err != nil {
			secondsEastOfUTC := int((7 * time.Hour).Seconds())
			jakarta = time.FixedZone("WIB", secondsEastOfUTC)
		}
		return jakarta
	}()

	// Create a custom config.
	cronx.NewManager(cronx.WithLocation(loc))
}

My job requires certain information like current wave number, how can I get this information?

This kind of information is stored inside metadata, which stored automatically inside context.

package main

import (
	"context"
	"errors"

	"github.com/rizalgowandy/cronx"
	"github.com/rizalgowandy/gdk/pkg/logx"
)

type subscription struct{}

func (subscription) Run(ctx context.Context) error {
	md, ok := cronx.GetJobMetadata(ctx)
	if !ok {
		return errors.New("cannot job metadata")
	}
	logx.INF(ctx, md, "subscription is running")
	return nil
}

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Functions

Chain returns a single interceptor from multiple interceptors.
GetJobMetadata returns job metadata from current context, and status if it exists or not.
GetJobName return the Job name by reflect the job.
No description provided by the author
NewFuncJob creates a wrapper type for a raw func with name.
NewJob creates a new job with default status and name.
NewManager create a command controller with a specific config.
NewServer creates a new HTTP server.
NewSideCarServer creates a new sidecar HTTP server.
No description provided by the author
SetJobMetadata stores current job metadata inside current context.
WithAlerter determines the alerter used to send notification for high latency job run detected.
WithAutoStartDisabled prevent the cron job from actually running.
WithInterceptor specifies Job wrappers to apply to all jobs added to this cron.
WithLocation overrides the timezone of the cron instance.
WithLowPriorityDownJobs puts the down jobs at the bottom of the list.
WithParser overrides the parser used for interpreting job schedules.
WithStorage determines the reader and writer for historical data.

# Constants

CtxKeyJobMetadata is context for cron job metadata.
No description provided by the author
SleepDuration defines the duration to sleep the server if the defined address is busy.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
StatusCodeDown describes that current job has failed to be registered.
StatusCodeError describes that last run has failed.
StatusCodeRunning describes that current job is currently running.
StatusCodeSuccess describes that current job is waiting for next execution time.
StatusCodeUp describes that current job has just been created.

# Variables

Default configuration for the manager.
Default configuration for the manager.
Default configuration for the manager.
DefaultParser supports the v1 where the first parameter is second.
Default configuration for the manager.

# Structs

No description provided by the author
FuncJob is a type to allow callers to wrap a raw func with name.
No description provided by the author
No description provided by the author
No description provided by the author
Manager controls all the underlying job.
Request is a parameter to return list of data with pagination.
No description provided by the author
ServerController is http server controller.
StatusData defines current job status.
No description provided by the author

# Interfaces

No description provided by the author
No description provided by the author

# Type aliases

Func is a type to allow callers to wrap a raw func.
No description provided by the author
No description provided by the author
Option represents a modification to the default behavior of the manager.
StatusCode describes current job status.