worksync

package module
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2023 License: MIT Imports: 9 Imported by: 2

README

Koi logo
Work Synchronizer

Schedule works for different types of workers on different machines backed by only a single `MySQL` table.

go version   license version

Why this library

  • Small Codebase
  • Minimum dependency on other libraries
  • Flexibility to integrate into workers

Download

go get github.com/mehditeymorian/worksync@latest

How the Sync Happens?

All the works are managed by a scheduler backed by MYSQL. The scheduler takes a list of work blueprints with the following attributes:

type Work struct {
	// unique name for the work
	Name   string
	// cron expression of when the worker is going to be executed
	Cron   string
	// number of times the work must be executed.
	// Note that it is only guaranteed that 
	// the number of workers acquiring this work not to surpass this value.
	MaxRun int64
}

The Scheduler then creates works before the schedule of each worker based on the MaxRun value. Then at the scheduled time, each worker tries to acquire work by updating the work status. If there is work with a Queued status, the worker will acquire the work. otherwise, it fails.

Note: each sequence of works is known by the worker name and a sequence value. These two values must be the same on the scheduler and on the worker side.

By default, the scheduler set sequence as the execution time formatted by time.DateTime. The sequence generator can be customized in the schedule's config.

How to Use

Create the following table in MYSQL

create table if not exists [DATABASE].[TABLE]
(
    id          int auto_increment
        primary key,
    created_at  datetime     null,
    name        varchar(255) null,
    status      int8         null,
    sequence    varchar(255) null,
    started_at  datetime     null,
    finished_at datetime     null
);

Then connect as follows:

package main

import (
	...
        // import the proper driver for connection
        _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err)
    }
    
    syncDB := worksync.NewDBConnection(db, TableName)

}

Worker Side

On the worker-side, it only requires calling the acquireWork before doing the work.

package main

func main() {

	workSync := worksync.NewSyncer(syncDB)
	
	fancyWorker.do(func() {
		success, fail, err := workSync.AcquireWork(name, now.Format(time.DateTime))
		if err != nil {
                    return
		}
		
		// actual work
	})

}

Manager Side

package main

import (
	"worksync"
)

func main() {

	works := []*worksync.Work{
		{
			Name:   name,
			Cron:   cronExpr,
			MaxRun: maxRun,
		},
		// list of works ...
	}

	scheduler, err := worksync.NewScheduler(syncDB, works, &worksync.SchedulerConfig{
		// when to create the works. in this case it will create the work if duration before execution time is less than 5sec.
		DurationBeforeSequence:    time.Duration(5) * time.Second,
		// interval to check for creating works
		SchedulerCheckingInterval: "@every 2s",
		SequenceGenerator:         nil,
	})

	// non-blocking
	scheduler.StartSchedule()


}

Cron Expressions

We use robfig/cron for handling Crons. Please refer to their documentation on how to write cron expressions. Link

Documentation

Index

Constants

View Source
const DefaultTableName = "works"

Variables

View Source
var (
	ErrNoWork                = errors.New("there is no work to do")
	ErrFailToUpdateStatus    = errors.New("failed to update status")
	ErrFailToAcquireWork     = errors.New("failed to acquire work")
	ErrFailToFinalizeAcquire = errors.New("failed to acquire work")

	ErrFailToInitWorkScheduler = errors.New("failed to initialize work scheduler")
)
View Source
var DefaultSchedulerConfig = &SchedulerConfig{
	DurationBeforeSequence:    time.Duration(10) * time.Minute,
	SchedulerCheckingInterval: "@every 1m",
	SequenceGenerator: func(schedule time.Time) string {
		return schedule.Format(time.DateTime)
	},
}

Functions

func NewDBConnection

func NewDBConnection(conn *sql.DB, tableName string) *db

Types

type SchedulerConfig

type SchedulerConfig struct {
	DurationBeforeSequence    time.Duration
	SchedulerCheckingInterval string
	SequenceGenerator         SequenceFunc
}

type SequenceFunc

type SequenceFunc func(schedule time.Time) string

SequenceFunc used to generate sequence for each work.

type Work

type Work struct {
	// unique name for the work
	Name string
	// cron expression of when the worker is going to be executed
	Cron string
	// number of times the work must be executed.
	// Note that it is only guaranteed that
	// the number of workers acquiring this work not to surpass this value.
	MaxRun int64
	// contains filtered or unexported fields
}

type WorkResultFunc

type WorkResultFunc func()

type WorkScheduler

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

func NewScheduler

func NewScheduler(db *db, works []*Work, config *SchedulerConfig) (*WorkScheduler, error)

func (*WorkScheduler) StartSchedule

func (w *WorkScheduler) StartSchedule()

func (*WorkScheduler) StopSchedule

func (w *WorkScheduler) StopSchedule()

type WorkStatus

type WorkStatus int8
const (
	// Queued Initial status of work before acquiring.
	Queued WorkStatus = iota + 1
	// Running indicates that the work is running by a worker.
	Running
	// Success status of work if the worker finish the work successfully.
	Success
	// Failed status of work if the worker finish the work with an error.
	Failed
)

type WorkSync

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

func NewSyncer

func NewSyncer(db *db) *WorkSync

func (*WorkSync) AcquireWork

func (w *WorkSync) AcquireWork(workName, sequence string) (WorkResultFunc, WorkResultFunc, error)

AcquireWork check database and try to acquire a work. It returns an error if there is no work to acquire or fail in the process of acquiring a work. If the acquiring process is successful, it returns success and fail functions to determine the result of the work. Calling either of these functions will update the status of the work in the database.

Directories

Path Synopsis
examples
scheduler command
worker command
test
master module
slave module

Jump to

Keyboard shortcuts

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