英文:
Want to stop http server remotely
问题
我想远程停止http服务器(我可以做到),但我也想在停止后收到一条指示已停止的消息。这给我带来了一些问题。我能找到的唯一解决方案如下所示,但我不认为这是理想的。
有人能提供一个更好的解决方案吗?问题是,除非我使用最后的goroutine,否则无法将最终消息发送给客户端。
代码如下:
//*************
func stopServer(ohtWriter http.ResponseWriter, phtRequest http.Request) {// 停止服务器
//************
var iBytesSent int
var oOsError os.Error
var sErmes string
println("停止服务器")
iBytesSent,oOsError = ohtWriter.Write([]byte("<html>来自服务器的消息 - 服务器已停止。</html>"))
if oOsError != nil {
sErmes = ". 错误 = " +oOsError.String()
} else {
sErmes = ". 写入无错误"
}
println("stopServer: 发送的字节数 = " +strconv.Itoa(iBytesSent) +sErmes)
ohtFlusher, tCanFlush := ohtWriter.(http.Flusher)
if tCanFlush {
ohtFlusher.Flush()
}
go func() {
time.Sleep(3e9)
os.Exit(0)
}()
}
英文:
I want to stop the http server remotely (which I can do), but I also want to receive a message indicating that it has been stopped after it has been stopped. That is causing me some problems. The only solution that I could find is as shown below, which I do not consider ideal.
Can anyone provide a better solution. The problem is that the final message sent to the client is not getting through unless I use the goroutine as shown at the end "go func() {".
Code is as follows:
<pre><code>
//*************
func stopServer(ohtWriter http.ResponseWriter, phtRequest http.Request) {// Stop The Server
//************
var iBytesSent int
var oOsError os.Error
var sErmes string
println("Stopping Server")
iBytesSent,oOsError = ohtWriter.Write([]byte("<html>Message from server - server now stopped.</html>"))
if oOsError != nil {
sErmes = ". Error = " +oOsError.String()
} else {
sErmes = ". No error on write"
}
println("stopServer: Bytes sent = " +strconv.Itoa(iBytesSent) +sErmes)
ohtFlusher, tCanFlush := ohtWriter.(http.Flusher)
if tCanFlush {
ohtFlusher.Flush()
}
go func() {
time.Sleep(3e9)
os.Exit(0)
}()
}
</code></pre>
答案1
得分: 2
是的,我认为如果没有http包的支持,优雅地关闭是不可能的。这可能会稍微好一些,但仍然会在此请求时关闭任何其他并发请求。也许可以尝试在Go问题跟踪器上提交一个功能请求。更好的方法是打开http包,并添加一个优雅关闭的方法,然后提交它。
**编辑:**我猜如果您控制应用程序中的所有http.Handlers,您可以使用适当的线程同步来计算正在处理的请求的数量,并修改下面的代码:a)在调用“shutdown”后拒绝新连接,b)在关闭之前等待所有正在处理的请求完成...
package main
import (
"http"
"os"
"io"
"log"
"strconv"
)
func main() {
http.HandleFunc("/", ServeHTTP)
http.ListenAndServe(":8081", nil)
}
const responseString = "Shutting down\n"
func ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("Content-Length", strconv.Itoa(len(responseString)))
io.WriteString(w, responseString)
f, canFlush := w.(http.Flusher)
if canFlush {
f.Flush()
}
conn, _, err := w.(http.Hijacker).Hijack()
if err != nil {
log.Fatalf("error while shutting down: %v", err)
}
conn.Close()
log.Println("Shutting down")
os.Exit(0)
}
英文:
Yeah I think without support from the http package, a graceful shutdown is not really possible. This is maybe a little bit less cringe-worthy, but will still slam closed any other concurrent requests in flight at the time of this request. Maybe try filing a feature request on the Go issue tracker. Better yet, open up the http package, and add a graceful shutdown method, and submit it.
Edit: I guess if you control all of the http.Handlers in your app, you could keep a count of in-flight requests (using appropriate thread synchronization), and modify the code below to a) refuse new connections once "shutdown" is called and b) wait for all in-flight requests to complete before shutting down...
package main
import (
"http"
"os"
"io"
"log"
"strconv"
)
func main() {
http.HandleFunc("/", ServeHTTP)
http.ListenAndServe(":8081", nil)
}
const responseString = "Shutting down\n"
func ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("Content-Length", strconv.Itoa(len(responseString)))
io.WriteString(w, responseString)
f, canFlush := w.(http.Flusher)
if canFlush {
f.Flush()
}
conn, _, err := w.(http.Hijacker).Hijack()
if err != nil {
log.Fatalf("error while shutting down: %v", err)
}
conn.Close()
log.Println("Shutting down")
os.Exit(0)
}
答案2
得分: 0
还没有尝试过,但直接使用http.ServerConn
可能会起作用。
英文:
Haven't tried it yet, but using http.ServerConn
directly might work.
答案3
得分: 0
这是一个足够简单的方法,适用于本地开发。
http://www.sergiotapia.me/how-to-stop-your-go-http-server/
package main
import (
"net/http"
"os"
"github.com/bmizerany/pat"
)
var mux = pat.New()
func main() {
mux.Get("/kill", http.HandlerFunc(kill))
http.Handle("/", mux)
http.ListenAndServe(":8080", nil)
}
func kill(w http.ResponseWriter, r *http.Request) {
os.Exit(0)
}
英文:
Here's a simple way that's good enough for local development.
http://www.sergiotapia.me/how-to-stop-your-go-http-server/
package main
import (
"net/http"
"os"
"github.com/bmizerany/pat"
)
var mux = pat.New()
func main() {
mux.Get("/kill", http.HandlerFunc(kill))
http.Handle("/", mux)
http.ListenAndServe(":8080", nil)
}
func kill(w http.ResponseWriter, r *http.Request) {
os.Exit(0)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论