A Scheduler For Goroutines

Posted by SingChia Blog on August 15, 2017

This document is for project go-scheduler, go-scheduler helps to manage goroutines, only needs to set three optional quotas:

  • the maximum count of goroutines
  • the maximum count of processed requests per interval
  • the maximum value of rate (processed requests per interval/ incoming requests per interval)

Actually go-sheduler only adjust count of goroutines to satisfy those quotas if set, the strategy is gradienter by default, if runtime statistics don’t match any quotas, go-sheduler starts to work.
Since scheduler manage goroutines to handle user’s Request which contains Data and Handler, the scheduler simple call Request.Handler(Request.Data).
note: three optional quotas are only undercontrolled in go-scheduler

How-to-use

go-scheduler supplies several easy-understand and easy-integrate interfaces, Let’s see an easy sample.

import (
    "fmt"
    "sync/atomic"
    "time"
    scheduler "github.com/singchia/go-scheduler"
)

func main() {
    sch := scheduler.NewScheduler()
    
    sch.SetMaxGoroutines(5000)
    sch.StartSchedule()
    
    var val int64
    for i := 0; i < 10*10000*10000; i++ {
        sch.PublishRequest(&scheduler.Request{Data: val, Handler: SchedulerHandler})
        atomic.AddInt64(&val, 1)
    }
    time.Sleep(time.Second * 5)
    fmt.Printf("maxValue: %d\n", maxValue)
    sch.Close()
}
    
var maxValue int64 = 0
    
func SchedulerHandler(data interface{}) {
    val, ok := data.(int64)
    if ok {
        if val > maxValue {
            maxValue = val
        }
    }
}

It’s not a good sample in production environment, but it does illustrate the usage of go-scheduler. After SetMaxGoroutines(5000), the max count of scheduler’s goroutines shouldn’t go beyond the range 5000, use StartSchedule to start the scheduler, publish the Request into the scheduler by using PublishRequest, then scheduler will handle the request undercontrol.

Installation

If you don’t have the Go development environment installed, visit the Getting Started document and follow the instructions. Once you’re ready, execute the following command:

go get -u github.com/singchia/go-scheduler

Interfaces

Scheduler.Interval

This should be set before call StartSchedule and bigger than 500us, if not set or less than 500us, default 200ms.

Scheduler.SetMaxGoroutines(int64)

This limits the max count of goroutines in go-scheduler, can be set at any time.

Scheduler.SetMaxProcessedReqs(int64)

This limits the max processed requests per interval, can be set at any time.

Scheduler.SetMaxRate(float64)

The rate is the value of processed requests / incoming requests, bigger means you want a faster speed to handle requests, can be set at any time.

Scheduler.SetDefaultHandler(scheduler.Handler)

If you want set a default handler when scheduler.Request.Handler not given, can be set at any time.

Scheduler.SetMonitor(scheduler.Monitor)

You can use this to monitor incoming requests, processed requests, shift(changing of goroutines), count of goroutines this interval, can be set at any time.

Scheduler.SetStrategy(scheduler.Strategy)

scheduler.Strategy is the key deciding how to shift(update) the count of goroutines, you can replace it as your own strategy.

Strategy

scheduler.Gradienter

Defaultly go-scheduler uses Gradienter as strategy, it behaves like:

if incoming requests == 0 then shrink 20%
if any quotas > max quotas then shrink the count of goroutines
	if quotas == 1 then shrink directly to MaxGoroutines
	else shrink 20%  
if all quotas < max quotas then expand randFloat * incomingReqs / (incomingReqs + maxCountGoroutines) * (maxCountGoroutines - currentCountGoroutines)

other strategies

In scheduler file, a circularLink.go exists, I was trying to look for next goroutines-updating by using history status, but temporarily no idea came up, if you have some idea welcome to contact me.