A concurrent scheduler for tasks with dependencies.
go get -u github.com/jackwakefield/cgscheduler
or
# go get -u github.com/golang/dep/cmd/dep
# dep init
dep ensure -add github.com/jackwakefield/cgscheduler
Create the scheduler with cgscheduler.New()
scheduler := cgscheduler.New()
// or, limit the number of concurrent tasks executed at once,
// by default this is set to runtime.NumCPU()
scheduler := cgscheduler.New(cgscheduler.ConcurrentTasks(2))
Tasks can be created with functions matching the signature func(ctx context.Context) error
// add a task which outputs "World!"
taskWorld := scheduler.AddTask(func(ctx context.Context) error {
fmt.Print("World!")
return nil
})
// add a task which outputs "Hello"
taskHello := scheduler.AddTask(func(ctx context.Context) error {
fmt.Print("Hello")
return nil
})
// add a task which outputs a space (" ")
taskSeparator := scheduler.AddTask(func(ctx context.Context) error {
fmt.Print(" ")
return nil
})
Dependencies can be created between tasks with Task.DependsOn
, which uses Scheduler.AddDependency
internally.
// execute taskHello before taskSeparator
taskSeparator.DependsOn(taskHello)
// execute taskSeparator before taskWorld
taskWorld.DependsOn(taskSeparator)
Run the scheduler with Scheduler.Run
, this accepts a context as a parameter and returns an error.
The scheduler returns when all tasks are complete, or a task has returned an error.
if err := scheduler.Run(context.Background()); err != nil {
log.Fatalln(err)
}
// Outputs:
// Hello World!
Internally the scheduler uses a Directed Acyclic Graph to represent the tasks as nodes and their dependencies as edges.
When the scheduler is ran, and when the graph state has changed since the scheduler was last ran, the tasks are topologically ordered into levels using the Coffman-Graham algorithm.