Search code examples
goconcurrencychannelgoroutine

how to do http.ListenAndServe() but passing a channel to it for retrieve a error signal or a success signal


I have this problem where the function http.ListenAndServe() blocks the goroutine, the simplified version of the original code was this:

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "visiting foo")
    })
    if err := http.ListenAndServe("127.0.0.1:8080", nil); err != nil {
        log.Fatal(err)
    }
    fmt.Println("app succesfully running in url http://127.0.0.1:8080")
}

The problem is that the success message doesn't get printed out because http.ListenAndServe() function blocks the goroutine, my first solution was this:

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "visiting foo")
    })
    go func() {
        if err := http.ListenAndServe("127.0.0.1:8080", nil); err != nil {
            log.Fatal(err)
        }
    }()
    fmt.Println("app succesfully running in url http://127.0.0.1:8080")
    var c chan struct{}
    <-c
}

This is a very reasonable solution but it got a problem and it's that if http.ListenAndServe() returns an error, the success message is also printed out, so another solution that I got was this but I don't like it, I hope you guys can help me with this:

package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "visiting foo")
    })
    go func() {
        if err := http.ListenAndServe("127.0.0.1:8080", nil); err != nil {
            log.Fatal(err)
        }
    }()
    someArbitraryDuration := 100 * time.Millisecond
    time.Sleep(someArbitraryDuration)
    fmt.Println("app succesfully running in url http://127.0.0.1:8080")
    var c chan struct{}
    <-c
}

I thought that in the net/http package there was some function that received a channel or callback function just like the Express JS framework has.

If you can help me with this, some way to pass a channel or callback to a function similar to ListenAndServe().

Unfortunately I couldn't get the code to work on Go Playground (Official Website).


Solution

  • If you want to print a success message after the server start accepting connection you can use net.Listen. For example:

        l, err := net.Listen("tcp", ":8080")
        if err == nil {
            fmt.Println("Listening on port 8080")
        }
        http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "Hello World")
        }))