Поведение сервера. GracefulStop () в golang - PullRequest
0 голосов
/ 22 апреля 2019

У меня есть сервер gRPC, и я реализовал постепенное отключение моего сервера gRPC примерно так

fun main() {
    //Some code
    term := make(chan os.Signal)
    go func() {
            if err := grpcServer.Serve(lis); err != nil {
                term <- syscall.SIGINT
            }
        }()

    signal.Notify(term, syscall.SIGTERM, syscall.SIGINT)
    <-term
    server.GracefulStop()
    closeDbConnections()
}

Это отлично работает. Если вместо этого я напишу логику grpcServer.Serve() в основной процедуре и вместо этого добавлю логику обработчика выключения в другую процедуру, операторы после server.GracefulStop() обычно не выполняются. Некоторые DbConnections закрываются, если closeDbConnections() выполняется вообще.

server.GracefulStop() - это блокирующий вызов. Определенно grpcServer.Serve() заканчивается до server.GracefulStop() завершения. Итак, сколько же времени занимает остановка основной программы после возврата этого вызова?

проблемный код

func main() {
    term := make(chan os.Signal)
    go func() {
        signal.Notify(term, syscall.SIGTERM, syscall.SIGINT)
        <-term
        server.GracefulStop()
        closeDbConnections()
    }()
    if err := grpcServer.Serve(lis); err != nil {
        term <- syscall.SIGINT
    }
}

Этот случай не работает, как ожидалось. После выполнения server.GracefulStop(), closeDbConnections() может запускаться или не запускаться (обычно не выполняется до завершения). Я тестировал последний случай, отправив SIGINT, нажав Ctrl-C с моего терминала.

Может кто-нибудь объяснить это поведение?

1 Ответ

0 голосов
/ 22 апреля 2019

Я не уверен в вашем вопросе (пожалуйста, уточните его), но я бы посоветовал вам провести рефакторинг вашего main следующим образом:

func main() {

   // ...

   errChan := make(chan error)
   stopChan := make(chan os.Signal)

   // bind OS events to the signal channel
   signal.Notify(stopChan, syscall.SIGTERM, syscall.SIGINT)

   // run blocking call in a separate goroutine, report errors via channel
   go func() {
        if err := grpcServer.Serve(lis); err != nil {
            errChan <- err
        }
    }()

   // terminate your environment gracefully before leaving main function
   defer func() {
      server.GracefulStop()
      closeDbConnections()
   }()

   // block until either OS signal, or server fatal error
   select {
      case err := <-errChan:
          log.Printf("Fatal error: %v\n", err) 
      case <-stopChan:
   }

Не думаю, что это хорошая идеясмешивать системные события и ошибки сервера, как вы делаете в своем примере: в случае сбоя Serve вы просто игнорируете ошибку и генерируете системное событие, которое на самом деле не произошло.Попробуйте другой подход, когда есть два транспорта (канала) для двух разных типов событий, которые вызывают завершение процесса.

...