Skip to content

Instantly share code, notes, and snippets.

@lajosbencz
Created November 7, 2023 22:01
Show Gist options
  • Save lajosbencz/32bc71159d08504661e452be0ece35fe to your computer and use it in GitHub Desktop.
Save lajosbencz/32bc71159d08504661e452be0ece35fe to your computer and use it in GitHub Desktop.
Go - Graceful shutdown of goroutines with channel signaling
package main
import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
const burstSize = 3
func main() {
defer fmt.Println("shut down gracefully.")
shutdown := make(chan os.Signal, 1)
defer close(shutdown)
signal.Notify(shutdown, os.Interrupt, syscall.SIGHUP, syscall.SIGINT)
eventChan := make(chan string, burstSize*3)
burstLimiter := make(chan struct{}, burstSize)
ticker := time.NewTicker(time.Second)
stopChan := make(chan struct{})
wg := sync.WaitGroup{}
// dummy event procuder
wg.Add(1)
go func() {
defer wg.Done()
defer close(eventChan)
ticker1 := time.NewTicker(time.Millisecond * 320)
ticker2 := time.NewTicker(time.Millisecond * 690)
for {
select {
case <-ticker1.C:
fmt.Println("procuding event from ticker1")
eventChan <- "ticker1"
case <-ticker2.C:
fmt.Println("procuding event from ticker2")
eventChan <- "ticker2"
case <-stopChan:
fmt.Println("stopped event producer")
ticker1.Stop()
ticker2.Stop()
return
}
}
}()
// burst limiter producer
wg.Add(1)
go func() {
defer wg.Done()
defer close(burstLimiter)
for {
select {
case <-ticker.C:
for i := 0; i < burstSize; i++ {
burstLimiter <- struct{}{}
}
case <-stopChan:
fmt.Println("stopped burst limiter")
return
}
}
}()
loop:
for {
select {
case <-shutdown:
close(stopChan)
for range eventChan {
// drain channel so it's not blocking the writer
}
break loop
case msg := <-eventChan:
<-burstLimiter
fmt.Printf("%s %s\n", time.Now(), msg)
}
}
fmt.Println("shutting down gracefully...")
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment