Skip to content

Grace manages long-running goroutines gracefully.

License

Notifications You must be signed in to change notification settings

beiping96/grace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Grace

Build Status GoDoc Go Report Card CI On Push

Grace manages long-running goroutines gracefully by trapping system signals and canceling context.Context.

import "github.com/beiping96/grace"

The core of Grace is type Goroutine func(ctx context.Context).

Usage

Simple

package main

import(
    "context"
    "time"
    "github.com/beiping96/grace"
)

func main() {
    // Register worker
    grace.Go(worker)

    // Start worker and hold main goroutine.
    // After process received system signal, 
    // worker should exit in two seconds,
    // otherwise, be killed.
    grace.Run(time.Second * time.Duration(2)) 
}

func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            // receive stop signal
            return
        default:
        }
        // do some job costs second
        time.Sleep(time.Second)      
    }
}

Pub/Sub

package main

import(
    "context"
    "time"
    "github.com/beiping96/grace"
)

func main() {
    // Register puber
    grace.Go(puber)
    // Register 2 suber
    for i := 0; i < 2; i++ { 
        grace.Go(suber) 
    }

    grace.Run(time.Second) // start
}

var (
    jobChan = make(chan struct{}, 1)
)

func puber(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            // receive stop signal
            close(jobChan)
            return
        default:
        }
        // load job
        var (
            job struct{}
        )
        // pub job
        jobChan <- job 
    }
}

func suber(ctx context.Context) {
    for job := range jobChan {
        // handle job
    	println(job)
    }
}

HTTPD

package main

import (
    "context"
    "net/http"
    "time"
    "github.com/beiping96/grace"
)

func httpd(ctx context.Context) {
    server := &http.Server{}
    
    grace.Go(func(ctx context.Context) {
        <-ctx.Done()
        server.Shutdown(context.Background())
    })
    
    server.ListenAndServe()
}

func main() {
    // Register httpd
    grace.Go(httpd)
    
    // Start
    // After process received system signal, 
    // wait all http connection closed is ten seconds
    grace.Run(time.Second * time.Duration(10)) 
}

Option

package main

import (
    "context"
    "time"
    "github.com/beiping96/grace"
)

func main() {
    // After one minute, the worker's ctx will be canceled
    grace.Go(worker, grace.OptionExpire(time.Minute))    
    
    // If worker stopped, it will be restart
    // The max number of restart is 2
    grace.Go(worker, grace.OptionRestart(2))
    
    // If worker stopped, it will be restart
    // The max number of restart is 2
    // Each worker can executed one minute
    grace.Go(worker, grace.OptionRestart(2),
                     grace.OptionExpire(time.Minute))
    
    // If worker stopped, it will be restart
    // The max number of restart is 2
    // All workers only have one minute to executed
    grace.Go(worker, grace.OptionExpire(time.Minute),
                     grace.OptionRestart(2))

    grace.Run(time.Second)
}


func worker(ctx context.Context) {}

Custom

package main

import (
    "log"
    "context"
    "syscall"
    "time"
    "github.com/beiping96/grace"
)

func main() {
    // Declare stop signals
    // Default is syscall.SIGINT, syscall.SIGQUIT or syscall.SIGTERM
    grace.Signal(syscall.SIGQUIT, syscall.SIGTERM)

    // Declare logger method
    // Default is os.Stdout
    grace.Log(log.Printf)

    // Declare process id folder
    // Default is unable
    grace.PID("./")
    
    // Register goroutine
    grace.Go(worker)
    
    // Register dynamic goroutine
    grace.Go(func(ctx context.Context) { grace.Go(worker) })

    // Never return
    // Stopped when receiving stop signal
    // or all goroutines are exit
    grace.Run(time.Second)
}

func worker(ctx context.Context) {}

Releases

No releases published

Packages

No packages published

Languages