Как добавить обратный вызов после в Gin framework

Мне нужно выйти из приложения с помощью os.Exit(0) ПОСЛЕ полного завершения HTTP-запроса. Мое приложение спрашивает другой сервер, нужно ли ему обновление, поэтому мне нужно выйти для выполнения самостоятельного обновления с перезагрузкой, но я не хочу прерывать текущий HTTP-запрос.

Когда я пытаюсь выйти в промежуточном программном обеспечении после c.Next() или в конце функции обработчика, браузер выдает ошибку: localhost didn’t send any data.

Как это можно сделать?


person sekrett    schedule 30.11.2017    source источник


Ответы (2)


Как вы говорите, ваша программа завершается до того, как HTTP-соединение завершится чисто - вам нужно дождаться завершения HTTP-транзакции, а затем выйти. К счастью, поскольку в Go 1.8 http.Server есть метод Shutdown, который делает то, что вам нужно.

Shutdown изящно завершает работу сервера, не прерывая никаких активных подключений. Выключение работает, сначала закрывая все открытые прослушиватели, затем закрывая все бездействующие соединения, а затем ожидая неопределенное время, пока соединения не вернутся в состояние бездействия, а затем отключаются.

Итак, общий подход будет таким:

exitChan := make(chan struct{})

// Get a reference to exitChan to your handlers somehow

h := &http.Server{
    // your config
}
go func(){
    h.ListenAndServe() // Run server in goroutine so as not to block
}()

<-exitChan // Block on channel
h.Shutdown(nil) // Shutdown cleanly with a timeout of 5 seconds

А затем exitChan <- struct{}{} в вашем обработчике/промежуточном программном обеспечении, когда требуется завершение работы.

См. также: https://stackoverflow.com/questions/39320025/how-to-stop-http-listenandserve

person wlcx    schedule 03.12.2017
comment
Да, это работает. Но для работы с Gin требуются дополнительные строки. - person sekrett; 05.12.2017
comment
Также нет 5-секундного тайм-аута, он сразу же завершает работу, и это хорошо. - person sekrett; 05.12.2017

Вы можете обратиться к этому примеру в их репозитории github:
мягкое закрытие

package main

import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "time"

    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.GET("/", func(c *gin.Context) {
        time.Sleep(5 * time.Second)
        c.String(http.StatusOK, "Welcome Gin Server")
    })

    srv := &http.Server{
        Addr:    ":8080",
        Handler: router,
    }

    go func() {
        // service connections
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s\n", err)
        }
    }()

    // Wait for interrupt signal to gracefully shutdown the server with
    // a timeout of 5 seconds.
    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt)
    <-quit
    log.Println("Shutdown Server ...")

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    if err := srv.Shutdown(ctx); err != nil {
        log.Fatal("Server Shutdown:", err)
    }
    log.Println("Server exiting")
}
person Ankit Deshpande    schedule 03.12.2018
comment
Подумайте также о предоставлении объяснения кода, чтобы увеличить долгосрочную ценность вашего ответа. - person Tiago Martins Peres 李大仁; 04.12.2018