本文涉及以下两个库

"github.com/fvbock/endless"  
"github.com/gin-gonic/gin"

gin为我们熟知的WEB封装框架,它是http中handle的实现:

package main

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	// 设置HTTP服务器的超时时间为5秒
	server := &http.Server{
		Addr:         ":8080",
		Handler:      r,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}

	r.GET("/hello", func(c *gin.Context) {
		time.Sleep(10 * time.Second) // 模拟耗时操作
		c.String(http.StatusOK, "Hello, World!")
	})

	server.ListenAndServe()
}

gin框架中并没有对 ReadTimeoutWriteTimeout 的控制,它默认启动时,这两个参数都为0既不请求超时也不限制响应超时。 以下实现了一个简易的http常链接,可以通过curl http://127.0.0.1/stream 进行测试,也可以在浏览器直接访问 http://127.0.0.1/stream`

package main  
  
import (  
	"fmt"  
	"github.com/gin-gonic/gin"  
	"time"  
)  
  
func main() {  
r := gin.Default()  
  
r.GET("/stream", func(c *gin.Context) {  
	c.Header("Content-Type", "text/event-stream")  
	c.Header("Cache-Control", "no-cache")  
	c.Header("Connection", "keep-alive")  
	c.Header("Access-Control-Allow-Origin", "*")  
	  
	messageChan := make(chan string)  
	  
	go func() {  
		ticker := time.NewTicker(1 * time.Second)  
		defer ticker.Stop()  
		  
		for {  
			select {  
				case <-ticker.C:  
					messageChan <- "This is a message"  
			}  
		}  
	}()  
	  
	var i int  
	for {  
		i++  
		message := <-messageChan  
			fmt.Fprintf(c.Writer, "data: %d.%s\n\n", i,message)  
			c.Writer.Flush()  
	}  
})  
  
r.Run(":8080")  
}

那么,上面的代码有一个问题,当代码有更新,需要重启时,如何优雅的的重启服务呢?endless 配合gin可以实现一个优雅的服务重启。 原理介绍:https://github.com/fvbock/endless/blob/master/examples/README.md

package main  
  
import (  
	"fmt"
	"github.com/fvbock/endless"  
	"github.com/gin-gonic/gin"  
	"time"  
)  
  
func main() {  
r := gin.Default()  
  
r.GET("/stream", func(c *gin.Context) {  
	c.Header("Content-Type", "text/event-stream")  
	c.Header("Cache-Control", "no-cache")  
	c.Header("Connection", "keep-alive")  
	c.Header("Access-Control-Allow-Origin", "*")  
	  
	messageChan := make(chan string)  
	  
	go func() {  
		ticker := time.NewTicker(1 * time.Second)  
		defer ticker.Stop()  
		  
		for {  
			select {  
				case <-ticker.C:  
					messageChan <- "This is a message"  
			}  
		}  
	}()  
	  
	var i int  
	for {  
		i++  
		message := <-messageChan  
			fmt.Fprintf(c.Writer, "data: %d.%s\n\n", i,message)  
			c.Writer.Flush()  
	}  
})  

s := endless.NewServer(":8080", r)  
s.ReadHeaderTimeout = 0  
s.WriteTimeout = 0  
s.MaxHeaderBytes = 1 << 20
_ = s.ListenAndServe()
}