gowebserver

Graceful stop of gin server


I'm trying to implement a clean way of gracefully stopping my gin server using a parent context passed to my class. Here the current code I have

Is there a cleaner way to do this? It feels like a lot of boilerplate code and unnessesary e.g. using an infinite loop for such an easy task.

func (instance *MyListener) Listen(ctx context.Context) error {
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()
    
    engine := gin.Default()
    engine.POST("/doStuff", func(c *gin.Context) {          
        instance.doStuff()
        c.Status(200)
    })

    instance.httpSrv = &http.Server {
        Addr:    ":8080",
        Handler: engine,
    }

    // Initializing the server in a goroutine so that
    // it won't block the graceful shutdown handling below
    go func() {
        if err := instance.httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            logging.Log.Error("Could not start listener", zap.Error(err))
        }
    }()

    loop:
    for {
        select {
            case <- ctx.Done():
                break loop
            default:
                time.Sleep(1000)
        }
    }

    ctx, cancel = context.WithTimeout(ctx, 2 * time.Second)
    if err := instance.httpSrv.Shutdown(ctx); err != nil {
        logging.Log.Error("Server forced to shutdown:", err)
    }

    return nil
}

Solution

  • This:

    loop:
    for {
        select {
            case <- ctx.Done():
                break loop
            default:
                time.Sleep(1000)
        }
    }
    

    Could be replaced with this:

    <- ctx.Done()
    

    And it would be just as effective and more efficient. Other than that, the solution you have seems clean, clear, and correct.