【问题标题】:Golang Clean shutdown on Signal Interrupt信号中断时 Golang Clean 关闭
【发布时间】:2021-03-29 06:04:51
【问题描述】:

我正在尝试找到一种有效的方法来关闭我所有的 go 例程,一旦我得到我的操作系统中断信号。在这里,我正在轮询事件(比如从某个队列中)并在 goroutine 中处理它。但是当我收到操作系统中断时,我想确保正在运行的作业在终止之前完成。只有在所有 goroutine 完成后,我还需要做一些额外的事情。下面的代码对我来说似乎很好,但是有没有更好/有效的方法来做到这一点?

package main

import (
    "fmt"
    "os"
    "os/signal"
    "sync"
    "syscall"
    "time" // or "runtime"
)

func something(wg *sync.WaitGroup){
    defer wg.Done()
    fmt.Println("something is happening here...")
    time.Sleep(10 * time.Second)
    fmt.Println("job done...")
}

func main() {

    c := make(chan os.Signal)
    mutex := sync.Mutex{}
    stop := make(chan int, 1)
    signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
    wg := sync.WaitGroup{}
    count := 0
    go func() {
        <-c
        currentTime := time.Now()
        fmt.Println("Interrupt signal got at: ", currentTime.String())
        // do not let the code shutdown without running everything we needed to do
        mutex.Lock()
        stop <- 1
        fmt.Println("Done .. try shutting down")
        wg.Wait()

        // do cleanup
        time.Sleep(3*time.Second)

        fmt.Println("All cleanup completed .. shut down")
        currentTime = time.Now()
        fmt.Println("Kill at : ", currentTime.String())
        mutex.Unlock()
    }()

    // This for loop is for reading messages from queue like sqs, and it has to be infinite loop because there might be scenarios where there are no events for period of time.
    for {            
        // read off of queue
        select {
        case stop <- 1:
            fmt.Println("Not stopped yet")
            wg.Add(1)
            go something(&wg)
            <- stop
            count ++
        default:
            // try getting the lock before exiting (so that other cleanups are done)
            mutex.Lock()
            fmt.Println("Done! All jobs completed: Jobs count",count)
            return
        }
        fmt.Println("Processing job -", count)
        time.Sleep(1 * time.Second)
    }
}

【问题讨论】:

标签: go concurrency signals goroutine


【解决方案1】:

我相信您的解决方案过于复杂。这可能是正确的,但这要简单得多:

func goroutine(wg *sync.WaitGroup,stop chan struct{}) {
  defer wg.Done()
   for {
     select {
       case <-stop:
          return
       default:
     }
    // do stuff
  }
}

func main() {
 stop:=make(chan struct{})

 // Setup signal handlers
 go func() {
        <-c
        // This will send the stop signal to all goroutines
        close(stop)
 }()
 // Start goroutines
 ...
 // wait for them to finish
wg.Wait()

【讨论】:

  • 非常有意义,使用“close”更干净。但是我有那个无限循环(最后的“for”循环)作为我的瓶颈,之后我不能 wg.wait() (成为无法访问的代码)。假设我有一些分布式排队系统(sqs/3rd 方事件系统,每次查询时都会返回不规则数量的事件,并且队列总是很忙),我们在一次长轮询时获得 10 条消息,在下一个循环中获得 5 条消息。我不希望 5 条消息等到前 10 条消息完成。
  • 如果你创建多个 goroutine 来处理消息,该解决方案仍然有效。你不应该需要那个 for 循环。
  • 是的,只要把整个东西放在 goroutine 中就可以了。谢谢
猜你喜欢
  • 1970-01-01
  • 2018-07-17
  • 2019-12-01
  • 2013-08-09
  • 2016-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多