How to notify when HTTP server starts successfully
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?
go
add a comment |
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?
go
1
Possible duplicate of get notified when http.Server starts listening
– Berkant
Nov 16 '18 at 6:52
Do you really need that? HTTP server start should be really fast. I would rather check to see what in your code makes it slow. Do you have any IO in handlers initializers?
– Dmitry Harnitski
Nov 16 '18 at 13:13
add a comment |
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?
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?
go
go
edited Nov 16 '18 at 8:17
Flimzy
40.2k1367100
40.2k1367100
asked Nov 16 '18 at 6:38
ComplexityComplexity
3,24522157
3,24522157
1
Possible duplicate of get notified when http.Server starts listening
– Berkant
Nov 16 '18 at 6:52
Do you really need that? HTTP server start should be really fast. I would rather check to see what in your code makes it slow. Do you have any IO in handlers initializers?
– Dmitry Harnitski
Nov 16 '18 at 13:13
add a comment |
1
Possible duplicate of get notified when http.Server starts listening
– Berkant
Nov 16 '18 at 6:52
Do you really need that? HTTP server start should be really fast. I would rather check to see what in your code makes it slow. Do you have any IO in handlers initializers?
– Dmitry Harnitski
Nov 16 '18 at 13:13
1
1
Possible duplicate of get notified when http.Server starts listening
– Berkant
Nov 16 '18 at 6:52
Possible duplicate of get notified when http.Server starts listening
– Berkant
Nov 16 '18 at 6:52
Do you really need that? HTTP server start should be really fast. I would rather check to see what in your code makes it slow. Do you have any IO in handlers initializers?
– Dmitry Harnitski
Nov 16 '18 at 13:13
Do you really need that? HTTP server start should be really fast. I would rather check to see what in your code makes it slow. Do you have any IO in handlers initializers?
– Dmitry Harnitski
Nov 16 '18 at 13:13
add a comment |
2 Answers
2
active
oldest
votes
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.
That makes sense. I tought that evenserveAndListen
is a blocking function, I would be able to solve this using a channel but it seems that it isn't :-)
– Complexity
Nov 16 '18 at 6:54
add a comment |
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.
Thanks for the clarification. And does the 'main' thread blocks until a channel is empty or how does that function in golang?
– Complexity
Nov 16 '18 at 7:02
So everything will exit once themain
function does. So yourWaitGroup
will block for you. An alternative would be to put theselect
-statement in a go routine and let theListenAndServe
block the exit of themain
function.
– poy
Nov 16 '18 at 7:07
This still will get to a 'Deadlock'.
– Complexity
Nov 16 '18 at 10:25
add a comment |
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53332667%2fhow-to-notify-when-http-server-starts-successfully%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
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.
That makes sense. I tought that evenserveAndListen
is a blocking function, I would be able to solve this using a channel but it seems that it isn't :-)
– Complexity
Nov 16 '18 at 6:54
add a comment |
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.
That makes sense. I tought that evenserveAndListen
is a blocking function, I would be able to solve this using a channel but it seems that it isn't :-)
– Complexity
Nov 16 '18 at 6:54
add a comment |
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.
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.
edited Nov 16 '18 at 7:07
answered Nov 16 '18 at 6:48
BerkantBerkant
357312
357312
That makes sense. I tought that evenserveAndListen
is a blocking function, I would be able to solve this using a channel but it seems that it isn't :-)
– Complexity
Nov 16 '18 at 6:54
add a comment |
That makes sense. I tought that evenserveAndListen
is a blocking function, I would be able to solve this using a channel but it seems that it isn't :-)
– Complexity
Nov 16 '18 at 6:54
That makes sense. I tought that even
serveAndListen
is a blocking function, I would be able to solve this using a channel but it seems that it isn't :-)– Complexity
Nov 16 '18 at 6:54
That makes sense. I tought that even
serveAndListen
is a blocking function, I would be able to solve this using a channel but it seems that it isn't :-)– Complexity
Nov 16 '18 at 6:54
add a comment |
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.
Thanks for the clarification. And does the 'main' thread blocks until a channel is empty or how does that function in golang?
– Complexity
Nov 16 '18 at 7:02
So everything will exit once themain
function does. So yourWaitGroup
will block for you. An alternative would be to put theselect
-statement in a go routine and let theListenAndServe
block the exit of themain
function.
– poy
Nov 16 '18 at 7:07
This still will get to a 'Deadlock'.
– Complexity
Nov 16 '18 at 10:25
add a comment |
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.
Thanks for the clarification. And does the 'main' thread blocks until a channel is empty or how does that function in golang?
– Complexity
Nov 16 '18 at 7:02
So everything will exit once themain
function does. So yourWaitGroup
will block for you. An alternative would be to put theselect
-statement in a go routine and let theListenAndServe
block the exit of themain
function.
– poy
Nov 16 '18 at 7:07
This still will get to a 'Deadlock'.
– Complexity
Nov 16 '18 at 10:25
add a comment |
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.
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.
answered Nov 16 '18 at 6:55
poypoy
6,56263465
6,56263465
Thanks for the clarification. And does the 'main' thread blocks until a channel is empty or how does that function in golang?
– Complexity
Nov 16 '18 at 7:02
So everything will exit once themain
function does. So yourWaitGroup
will block for you. An alternative would be to put theselect
-statement in a go routine and let theListenAndServe
block the exit of themain
function.
– poy
Nov 16 '18 at 7:07
This still will get to a 'Deadlock'.
– Complexity
Nov 16 '18 at 10:25
add a comment |
Thanks for the clarification. And does the 'main' thread blocks until a channel is empty or how does that function in golang?
– Complexity
Nov 16 '18 at 7:02
So everything will exit once themain
function does. So yourWaitGroup
will block for you. An alternative would be to put theselect
-statement in a go routine and let theListenAndServe
block the exit of themain
function.
– poy
Nov 16 '18 at 7:07
This still will get to a 'Deadlock'.
– Complexity
Nov 16 '18 at 10:25
Thanks for the clarification. And does the 'main' thread blocks until a channel is empty or how does that function in golang?
– Complexity
Nov 16 '18 at 7:02
Thanks for the clarification. And does the 'main' thread blocks until a channel is empty or how does that function in golang?
– Complexity
Nov 16 '18 at 7:02
So everything will exit once the
main
function does. So your WaitGroup
will block for you. An alternative would be to put the select
-statement in a go routine and let the ListenAndServe
block the exit of the main
function.– poy
Nov 16 '18 at 7:07
So everything will exit once the
main
function does. So your WaitGroup
will block for you. An alternative would be to put the select
-statement in a go routine and let the ListenAndServe
block the exit of the main
function.– poy
Nov 16 '18 at 7:07
This still will get to a 'Deadlock'.
– Complexity
Nov 16 '18 at 10:25
This still will get to a 'Deadlock'.
– Complexity
Nov 16 '18 at 10:25
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53332667%2fhow-to-notify-when-http-server-starts-successfully%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Possible duplicate of get notified when http.Server starts listening
– Berkant
Nov 16 '18 at 6:52
Do you really need that? HTTP server start should be really fast. I would rather check to see what in your code makes it slow. Do you have any IO in handlers initializers?
– Dmitry Harnitski
Nov 16 '18 at 13:13