How to notify when HTTP server starts successfully - go

I'm trying to start an HTTP server in Go, and when the server is started, a message should be printed, in case of an error, an error message should be printed.
Given the following code:
const (
HTTPServerPort = ":4000"
)
func main() {
var httpServerError = make(chan error)
var waitGroup sync.WaitGroup
setupHTTPHandlers()
waitGroup.Add(1)
go func() {
defer waitGroup.Done()
httpServerError <- http.ListenAndServe(HTTPServerPort, nil)
}()
if <-httpServerError != nil {
fmt.Println("The Logging API service could not be started.", <-httpServerError)
} else {
fmt.Println("Logging API Service running # http://localhost" + HTTPServerPort)
}
waitGroup.Wait()
}
When I do start the application, I don't see anything printed to the console, where I would like to see:
Logging API Service running # http://localhost:4000
When I change the port to an invalid one, the following output is printed to the console:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
...app.go:45 +0x107
exit status 2
Could anyone point me in the right direction so that I know what I'm doing wrong with this implementation?

You can't do this unless you change the logic in your code or use Listen and Serve separately. Because ListenAndServe is a blocking function. If there something unexpected happens, it will return you an error. Provided it is not, it will keep blocking running the server. There is neither an event that is triggered whenever a server is started.
Let's run Listen and Serve separately then.
l, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
}
// Signal that server is open for business.
if err := http.Serve(l, rootHandler); err != nil {
// handle error
}
See https://stackoverflow.com/a/44598343/4792552.
P.S. net.Listen doesn't block because it runs in background. In other means, it simply spawns a socket connection in OS level and returns you with the details/ID of it. Thus, you use that ID to proxy orders to that socket.

The issue is that your if statement will always read from the httpServerError channel. However the only time something writes to that is if the server fails.
Try a select statement:
select{
case err := <-httpServerError
fmt.Println("The Logging API service could not be started.", err)
default:
fmt.Println("Logging API Service running # http://localhost" + HTTPServerPort
}
The default case will be ran if the channel does not have anything on it.
Notice this does not read from the channel twice like your example. Once you read a value from a channel, its gone. Think of it as a queue.

Related

Go GRPC client disconnect terminates Go server

Bit of a newb to both Go and GRPC, so bear with me.
Using go version go1.14.4 windows/amd64, proto3, and latest grpc (1.31 i think). I'm trying to set up a bidi streaming connection that will likely be open for longer periods of time. Everything works locally, except if I terminate the client (or one of them) it kills the server as well with the following error:
Unable to trade data rpc error: code = Canceled desc = context canceled
This error comes out of this code server side
func (s *exchangeserver) Trade(stream proto.ExchageService_TradeServer) error {
endchan := make(chan int)
defer close(endchan)
go func() {
for {
req, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatal("Unable to trade data ", err)
break
}
fmt.Println("Got ", req.GetNumber())
}
endchan <- 1
}()
go func() {
for {
resp := &proto.WordResponse{Word: "Hello again "}
err := stream.Send(resp)
if err != nil {
log.Fatal("Unable to send from server ", err)
break
}
time.Sleep(time.Duration(500 * time.Millisecond))
}
endchan <- 1
}()
<-endchan
return nil
}
And the Trade() RPC is so simple it isn't worth posting the .proto.
The error is clearly coming out of the Recv() call, but that call blocks until it sees a message, like the client disconnect, at which point I would expect it to kill the stream, not the whole process. I've tried adding a service handler with HandleConn(context, stats.ConnStats) and it does catch the disconnect before the server dies, but I can't do anything with it. I've even tried creating a global channel that the serve handler pushes a value into when HandleRPC(context, stats.RPCStats) is called and only allowing Recv() to be called when there's a value in the channel, but that can't be right, that's like blocking a blocking function for safety and it didn't work anyway.
This has to be one of those real stupid mistakes that beginner's make. Of what use would GPRC be if it couldn't handle a client disconnect without dying? Yet I have read probably a trillion (ish) posts from every corner of the internet and noone else is having this issue. On the contrary, the more popular version of this question is "My client stream stays open after disconnect". I'd expect that issue. Not this one.
Im not 100% sure how this is supposed to behave but I note that you are starting separate receive and send goroutines up at the same time. This might be valid but is not the typical approach. Instead you would usually receive what you want to process and then start a nested loop to handle the reply .
See an example of typical bidirectional streaming implementation from here: https://grpc.io/docs/languages/go/basics/
func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {
for {
in, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
key := serialize(in.Location)
... // look for notes to be sent to client
for _, note := range s.routeNotes[key] {
if err := stream.Send(note); err != nil {
return err
}
}
}
}
sending and receiving at the same time might be valid for your use case but if that is what you are trying to do then I believe your handling of the channels is incorrect. Either way, please read on to understand the issue as it is a common one in go.
You have a single channel which only blocks until it receives a single message, once it unblocks the function ends and the channel is closed (by defer).
You are trying to send to this channel from both your send and receive
loop.
When the last one to finish tries to send to the channel it will have been closed (by the first to finish) and the server will panic. Annoyingly, you wont actually see any sign of this as the server will exit before the goroutine can dump its panic (no clues - probably why you landed here)
see an example of the issue here (grpc code stripped out):
https://play.golang.org/p/GjfgDDAWNYr
Note: comment out the last pause in the main func to stop showing the panic reliably (as in your case)
So one simple fix would probably be to simply create two separate channels (one for send, one for receive) and block on both - this however would leave the send loop open necessarily if you don't get a chance to respond so probably better to structure like the example above unless you have good reason to pursue something different.
Another possibility is some sort server/request context mix up but I'm pretty sure the above will fix - drop an update with your server setup code if your still having issues after the above changes

How to elegantly shut down gorilla websocket reader?

I have a websocket client which spins a goroutine, using Conn.ReadJSON to read incoming JSON messages.
I would like the goroutine to be able to nicely react to ctx.Done(), hence I wrote the following code:
for {
msg := new(message)
select {
case <- ctx.Done():
fmt.Println("Halting gracefully")
return
default:
err := Conn.ReadJSON(&msg)
if err != nil {
fmt.Println(err)
break
}
c.inbound <- *msg
}
}
Obviously, in the current state, ReadJSON is a non-blocking function, hence it is launched and then the execution stops somewhere within (not sure where) as it waits for a message to be received.
This means that it will never block at the select statement and hence it will never handle ctx.Done() appropriately.
Gorilla documentation doesn't show any case <- IsThereAnyNewMessage() available.
How can it be handled elegantly?

How to make my function return to Slack right away?

I'm trying to develop a simple API for Slack and I want to return something to the user right away to avoid the 3000 ms timeout.
Here are my questions:
Why the This should be printed to Slack first doesn't get printed right away, instead I only got the last message which is The long and blocking process completed? But it appears in ngrok log though.
Why is my function still reaching the 3000 ms limit even though I'm already using a go routine? Is it because of the done channel?
func testFunc(w http.ResponseWriter, r *http.Request) {
// Return to the user ASAP to avoid 3000ms timeout.
// But this doesn't work. Nothing is returned but
// the message appeared in ngrok log.
fmt.Fprintln(w, "This should be printed to Slack first!")
// Get the response URL.
r.ParseForm()
responseURL := r.FormValue("response_url")
done := make(chan bool)
go func() {
fmt.Println("Warning! This is a long and blocking process.")
time.Sleep(5 * time.Second)
done <- true
}()
// This works! I received this message. But I still reached the 3000ms timeout.
func(d bool) {
if d == true {
payload := map[string]string{"text": "The long and blocking process completed!"}
j, err := json.Marshal(payload)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
http.Post(responseURL, "application/json", bytes.NewBuffer(j))
}
}(<-done)
}
http.ResponseWriter streams are buffered by default. If you want data to be sent to a client in realtime (e.g. HTTP SSE), you need to flush the stream after each 'event':
wf, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Streaming unsupported!", http.StatusInternalServerError)
return
}
fmt.Fprintln(w, "This should be printed to Slack first!")
wf.Flush()
Flushing is expensive - so take advantage of go's buffering. There will always be an implicit flush once your handler finally exits (hence why you saw your output 'late').
I am learning stage of golang. Here is my understanding:
1. any operations with channel is blocking
2. You are writing on the channel in the
go func() {
fmt.Println("Warning! This is a long and blocking process.")
time.Sleep(5 * time.Second)
done <- true
}()
The scheduler is still moving in the main function and trying to read from the channel but it is waiting to see, something has written on the channel or not. So it got blocked, when the above function is done with writing on the channel, controls came back and main start executing again.
Note: Experts will be able to explain better.

How to place http.Serve in its own goroutine if it blocks?

http.Serve either returns an error as soon as it is called or blocks if successfully executing.
How can I make it so that if it blocks it does so in its own goroutine? I currently have the following code:
func serveOrErr(l net.Listener, handler http.Handler) error {
starting := make(chan struct{})
serveErr := make(chan error)
go func() {
starting <- struct{}{}
if err := http.Serve(l, handler); err != nil {
serveErr <- err
}
}()
<-starting
select {
case err := <-serveErr:
return err
default:
return nil
}
}
This seemed like a good start and works on my test machine but I believe that there are no guarantees that serveErr <- err would be called before case err := <-serveErr therefore leading to inconsistent results due to a data race if http.Serve were to produce an error.
http.Serve either returns an error as soon as it is called or blocks if successfully executing
This assumption is not correct. And I believe it rarely occurs. http.Serve calls net.Listener.Accept in the loop – an error can occur any time (socket closed, too many open file descriptors etc.). It's http.ListenAndServe, usually being used for running http servers, which often fails early while binding listening socket (no permissions, address already in use).
In my opinion what you're trying to do is wrong, unless really your net.Listener.Accept is failing on the first call for some reason. Is it? If you want to be 100% sure your server is working, you could try to connect to it (and maybe actually transmit something), but once you successfully bound the socket I don't see it really necessary.
You could use a timeout on your select statement, e.g.
timeout := time.After(5 * time.Millisecond) // TODO: ajust the value
select {
case err := <-serveErr:
return err
case _ := <- timeout:
return nil
}
This way your select will block until serveErr has a value or the specified timeout has elapsed. Note that the execution of your function will therefore block the calling goroutine for up to the duration of the specified timeout.
Rob Pike's excellent talk on go concurrency patterns might be helpful.

How to reliably unlink() a Unix domain socket in Go programming language

I have a Go program hosting a simple HTTP service on localhost:8080 so I can connect my public nginx host to it via the proxy_pass directive, as a reverse proxy to serve part of my site's requests. This is all working great, no problems there.
I want to convert the Go program to host the HTTP service on a Unix domain socket instead of a local TCP socket for improved security and to reduce the unnecessary protocol overhead of TCP.
PROBLEM:
The problem is that Unix domain sockets cannot be reused once they are bind() to, even after program termination. The second time (and every time after) I run the Go program it exits with a fatal error "address already in use".
Common practice is to unlink() Unix domain sockets (i.e. remove the file) when the server shuts down. However, this is tricky in Go. My first attempt was to use the defer statement in my main func (see below), but it is not getting run if I interrupt the process with a signal like CTRL-C. I suppose this is to be expected. Disappointing, but not unexpected.
QUESTION: Is there a best practice on how to unlink() the socket when the server process shuts down (either gracefully or ungracefully)?
Here's part of my func main() that starts the server listening for reference:
// Create the HTTP server listening on the requested socket:
l, err := net.Listen("unix", "/tmp/mysocket")
if err != nil {
log.Fatal(err)
} else {
// Unix sockets must be unlink()ed before being reused again.
// Unfortunately, this defer is not run when a signal is received, e.g. CTRL-C.
defer func() {
os.Remove("/tmp/mysocket")
}()
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
}
Here is the complete solution I used. The code I posted in my question was a simplified version for clear demonstration purposes.
// Create the socket to listen on:
l, err := net.Listen(socketType, socketAddr)
if err != nil {
log.Fatal(err)
return
}
// Unix sockets must be unlink()ed before being reused again.
// Handle common process-killing signals so we can gracefully shut down:
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
go func(c chan os.Signal) {
// Wait for a SIGINT or SIGKILL:
sig := <-c
log.Printf("Caught signal %s: shutting down.", sig)
// Stop listening (and unlink the socket if unix type):
l.Close()
// And we're done:
os.Exit(0)
}(sigc)
// Start the HTTP server:
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
I sure hope this is good and effective Go code that would make the Go authors proud. It certainly looks so to me. If it is not, that would be embarrassing on my part. :)
For anyone curious, this is part of https://github.com/JamesDunne/go-index-html which is a simple HTTP directory listing generator with some extra features that web servers don't give you out of the box.
You can end your main func with the signal handler and spawn separate go routines for your other tasks instead. That way, you can leverage the defer mechanism and handle all (signal-based or not) shut downs cleanly:
func main() {
// Create the HTTP server listening on the requested socket:
l, err := net.Listen("unix", "/tmp/mysocket")
if err != nil {
log.Fatal(err)
return
}
// Just work with defer here; this works as long as the signal handling
// happens in the main Go routine.
defer l.Close()
// Make sure the server does not block the main
go func() {
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
}()
// Use a buffered channel so we don't miss any signals
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)
// Block until a signal is received.
s := <-c
fmt.Println("Got signal:", s)
// ...and exit, running all the defer statements
}
In modern Go, you may use the syscall.Unlink() - docs here:
import (
"net"
"syscall"
...
)
...
socketpath := "/tmp/somesocket"
// carry on with your socket creation:
addr, err := net.ResolveUnixAddr("unixgram", socketpath)
if err != nil {
return err;
}
// always remove the named socket from the fs if its there
err = syscall.Unlink(socketpath)
if err != nil {
// not really important if it fails
log.Error("Unlink()",err)
}
// carry on with socket bind()
conn, err := net.ListenUnixgram("unixgram", addr);
if err != nil {
return err;
}

Resources