worker and http server graceful shutdown

I am trying to create a worker and an HTTP server which start independently, and listen for terminations and exit gracefully upon completion.

For some reason, the worker starts, but the HTTP server does not, until the SIGTERM event is sent. Only after the sigterm event is sent, then the http server starts. Where is the problem with the following?

output

https://gosamples.dev is the best
https://gosamples.dev is the best
https://gosamples.dev is the best
^C2023/05/27 15:07:52 Listening on HTTP server port: 

Process finished with the exit code 0

code

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"
    "sync"
    "syscall"
    "time"
)

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    
    go func() {
        signals := make(chan os.Signal, 1)
        signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
        <-signals

        cancel()
    }()

    var wg sync.WaitGroup

    wg.Add(1)
    go func() {
        if err := myWorker(ctx); err != nil {
            cancel()
        }
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        if err := startServer(ctx); err != nil {
            cancel()
        }
        wg.Done()
    }()

    wg.Wait()
}

func myWorker(ctx context.Context) error {
    shouldStop := false

    go func() {
        <-ctx.Done()
        shouldStop = true
    }()

    for !shouldStop {
        fmt.Println("https://gosamples.dev is the best")
        time.Sleep(1 * time.Second)
    }

    return nil
}

func startServer(ctx context.Context) error {
    var srv http.Server

    go func() {
        <-ctx.Done() // Wait for the context to be done

        // Shutdown the server
        if err := srv.Shutdown(context.Background()); err != nil {
            // Error from closing listeners, or context timeout:
            log.Printf("HTTP server Shutdown: %v", err)
        }
    }()

    if err := srv.ListenAndServe(); err != http.ErrServerClosed {
        // Error starting or closing listener:
        return fmt.Errorf("HTTP server ListenAndServe: %w", err)
    }

    log.Printf("Listening on HTTP server port: %s", srv.Addr)

    http.HandleFunc("/readiness", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(200)
    })
    http.HandleFunc("/liveness", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(200)
    })

    return nil
}


Comments

Popular posts from this blog

Today Walkin 14th-Sept

Spring Elasticsearch Operations

Hibernate Search - Elasticsearch with JSON manipulation