Reputation: 117
I have a function that start a Listener.
func startListener(string config) error {
return http.ListenAndServe(config, nil)
}
I run this function as a go routine in another function:
func Stuff() {
go startListener("0.0.0.0:8080")
doOtherStuff()
}
When I don't handle errors, doOtherStuff()
executes concurrently with startListener()
.
But I want to handle errors in my Go Routine. I created a channel that receive the error:
func Stuff() {
errChan := make(chan error, 1)
go func() {
errChan <- startListener("0.0.0.0:8080")
}()
if err := <-errChan; err != nil {
fmt.Printf("Error received from goroutine: %v\n", err)
} else {
fmt.Println("Goroutine completed without error")
}
doOtherStuff()
}
Problem is that when there is no error, doOtherStuff()
is never executed. The entire program flow hangs because it is listening on port 8080.
How can I handle error without hanging my program ?
Upvotes: -3
Views: 44
Reputation: 1646
You cannot rely on the error channel or the error returned from the call startListener
to confirm that the server started successfully or not since it is a blocking call.
Do a Health check or similar call to confirm that the server started successfully.
I belive that you are planning to run some post jobs once the server started successfully. So instead depending on the return error, Register the post jobs in a goroutine which will wait for the successful server start like shown below,
var waitForServerStart = make(chan bool)
func registerPostJob() {
fmt.Println("Waiting for the server start trigger")
<-waitForServerStart
fmt.Println("Received the signal to start post jobs")
for i := 0; i < 3; i++ {
resp, _ := http.Get("http://localhost:8080/")
if resp.StatusCode == http.StatusOK {
fmt.Println("Seems server started successfully")
doOtherStuff()
return
}
time.Sleep(1 * time.Second)
}
}
func startListener(config string) error {
handler := http.NewServeMux()
handler.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
return http.ListenAndServe(config, handler)
}
func doOtherStuff() {
fmt.Println("doOtherStuff executed")
}
func Stuff() {
go registerPostJob()
// other stuffs
time.Sleep(3 * time.Second)
// took time say 3 seconds
close(waitForServerStart)
if err := startListener("localhost:8080"); err != nil {
fmt.Printf("Error received from goroutine: %v\n", err)
}
}
Hope it helps.
Upvotes: 1