Home  >  Article  >  Backend Development  >  How to Gracefully Shut Down a Go HTTP Server After Returning a Response?

How to Gracefully Shut Down a Go HTTP Server After Returning a Response?

DDD
DDDOriginal
2024-10-28 19:12:29145browse

How to Gracefully Shut Down a Go HTTP Server After Returning a Response?

Shutting Down HTTP Server After Returning Response

In this scenario, you have built a Go command-line bot that interacts with the Instagram API. To obtain the access token, you start a local HTTP server to capture the redirect URI. However, you encounter an issue while attempting to manually shut down the server after retrieving the access token.

Problem:

"Server Closed" and "Invalid Memory Address"Errors Occur When Shutting Down the Server

Analysis:

The errors you encounter indicate that the HTTP server is being shut down prematurely before all connections are closed gracefully. This can occur due to asynchronous behavior in the HTTP handler and the server shutdown process.

Solution 1: Using Context.WithCancel:

Consider using context.WithCancel to create a context that can be canceled when the access token is retrieved. Pass this context to the HTTP handler and use CancelFunc to gracefully shut down the server when the context is closed.

<code class="go">package main

import (
    "context"
    "io"
    "log"
    "net/http"
)

func main() {
    ctx, cancel := context.WithCancel(context.Background())

    http.HandleFunc("/quit", func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Bye\n")
        cancel()
    })
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Hi\n")
    })

    srv := &http.Server{Addr: ":8080"}
    go func() {
        err := srv.ListenAndServe()
        if err != http.ErrServerClosed {
            log.Println(err)
        }
    }()

    <-ctx.Done()

    err := srv.Shutdown(context.Background())
    if err != nil {
        log.Println(err)
    }

    log.Println("done.")
}</code>

Solution 2: Using Same Context Across Functions:

You can also use the same context across multiple HTTP handlers and the main function to ensure that all functions are notified when the server should shut down.

<code class="go">package main

import (
    "context"
    "io"
    "log"
    "net/http"
)

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Hi\n")
    })
    http.HandleFunc("/quit", func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Bye\n")
        cancel()
    })
    srv := &http.Server{Addr: ":8080"}
    go func() {
        if err := srv.ListenAndServe(); err != nil {
            log.Printf("Httpserver: ListenAndServe() error: %s", err)
        }
    }()
    <-ctx.Done()

    if err := srv.Shutdown(ctx); err != nil && err != context.Canceled {
        log.Println(err)
    }
    log.Println("done.")
}</code>

Conclusion:

By using context.WithCancel or passing the same context across multiple functions, you can ensure that the HTTP server shuts down gracefully after all connections have been closed. This will prevent the errors you are currently encountering.

The above is the detailed content of How to Gracefully Shut Down a Go HTTP Server After Returning a Response?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn