Web服务孵化


web框架在Gin框架的基础上又封装了一层,包括服务进程管理、路由中间件、启动项自定义加载等
其中,服务进程的管理式型支持三种

  • Golang原生http Server启动模式
  • oversee Master/Slave启动模式,Master是监控Slave进程启停的管理单元,Slave提供对外服务
  • gracehttp 带有信号处理的独立进程启动模式,当接收到SIGUSR2 信号量时,关闭自身服务并在退出前启动新的服务进程

配置服务进程管理模式

在这里特别说明一下,我们所有组件、框架的配置文件存放位置、格式以及用法都是一致的,可参考Gaea 的配置文件

  1. [Server]
  2. //...
  3. ;进程管理模式
  4. grace=true

grace控制是否开启平滑重启,取值为:true 开启;false 关闭

  • 开启
  • 默认为oversee 模式,配合supervisor的信号指令可以实现服务无间断运行
  • gracehttp模式,也支持平滑重启,但是无法和supervisor结合使用,所以设置成了可选项
  • 关闭
  • Golang原生的启动模式,只能做到安全退出,即收到服务终止信号时,可以保证正在处理的任务正常结束

使用hera孵化web服务

在任一地方创建一个main.go 文件,然后执行命令go mod tidy.注:*在没有特殊说明的情况下,我们的依赖管理统一使用go mod

创建一个极简的web服务
  1. //main.go
  2. package main
  3. import (
  4. "github.com/tal-tech/xesGoKit/xesgin"
  5. bs "github.com/tal-tech/xesServer/bootstrap"
  6. "github.com/tal-tech/xesServer/ginhttp"
  7. _ "github.com/tal-tech/xesTools/expvarutil"
  8. "github.com/gin-gonic/gin"
  9. "log"
  10. "net/http"
  11. )
  12. func main() {
  13. s := ginhttp.NewServer()
  14. engine := s.GetGinEngine()
  15. engine.GET("/index", demoFun)
  16. s.AddServerBeforeFunc(bs.InitTraceLogger("XueYan", "0.1"))
  17. er := s.Serve()
  18. if er != nil {
  19. log.Printf("Server stop err:%v", er)
  20. } else {
  21. log.Printf("Server exit")
  22. }
  23. }
  24. func demoFun(ctx *gin.Context){
  25. ctx.JSON(http.StatusOK, xesgin.Success("hello world!"))
  26. }

编译&运行
  1. $ go build main.go
  2. $ ./main
  3. 2019/12/28 16:39:51 CONF INIT,path:../conf/conf.ini
  4. 2019/12/28 16:39:51 [expvarutil] Expvar not enabled
  5. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
  6. - using env: export GIN_MODE=release
  7. - using code: gin.SetMode(gin.ReleaseMode)
  8. [GIN-debug] GET /index --> main.demoFun (1 handlers)
  9. [16:39:51 CST 2019/12/28] [INFO] (server.go:57:561420000000001 localhost.localdomain) GIN-Server http server start and serve:

访问API

ginhttp Server 的默认配置如下:

  1. func DefaultOptions() ServerOptions {
  2. return ServerOptions{
  3. Addr: ":10088", //web监听端口
  4. ReadTimeout: 5 * time.Second, //读超时时间
  5. WriteTimeout: 5 * time.Second, //响应超时时间
  6. IdleTimeout: 5 * time.Second, //链接空闲时间
  7. }
  8. }

curl 测试

  1. $ curl http://127.0.0.1:10088/index
  2. {"code":0,"data":"hello world!","msg":"ok","stat":1}

至此,您已经成功创建了一个web服务!

当然我们还提供了其它丰富的功能,下面我们看一个实战项目

实战应用案例

我们的web框架Gaea的核心代码就是利用Hera孵化器生成的

服务主入口文件:

  1. //文件位置:https://github.com/tal-tech/gaea/blob/master/main/main.go
  2. package main
  3. import (
  4. "log"
  5. "runtime/debug"
  6. "gaea/app/router"
  7. "gaea/version"
  8. "github.com/tal-tech/xesGoKit/middleware"
  9. bs "github.com/tal-tech/hera/bootstrap"
  10. "github.com/tal-tech/hera/ginhttp"
  11. "github.com/tal-tech/xesTools/confutil"
  12. _ "github.com/tal-tech/xesTools/expvarutil"
  13. "github.com/tal-tech/xesTools/flagutil"
  14. "github.com/spf13/cast"
  15. )
  16. func main() {
  17. //show version
  18. ver := flagutil.GetVersion()
  19. if *ver {
  20. version.Version()
  21. return
  22. }
  23. //配置文件加载和解析模块
  24. confutil.InitConfig()
  25. //panic恢复
  26. defer recovery()
  27. //通过Hera 生成一个Gin服务
  28. s := ginhttp.NewServer()
  29. //获取Gin引擎
  30. engine := s.GetGinEngine()
  31. //装载默认中间件
  32. engine.Use(middleware.Logger(), middleware.Recovery(), middleware.XesLoggerMiddleware(), middleware.PerfMiddleware(), middleware.TraceMiddleware(), middleware.RequestHeader())
  33. //中间件绑定到路由上
  34. router.RegisterRouter(engine)
  35. //服务启动前的Hooks
  36. s.AddServerBeforeFunc(bs.InitLoggerWithConf(), bs.InitTraceLogger("XueYan", "0.1"), bs.InitPerfutil(), bs.InitPprof(), s.InitConfig())
  37. //服务结束后的Hooks
  38. s.AddServerAfterFunc(bs.CloseLogger())
  39. //启动服务,没有发生错误的情况下会阻塞在这里
  40. er := s.Serve()
  41. if er != nil {
  42. log.Printf("Server stop err:%v", er)
  43. } else {
  44. log.Printf("Server exit")
  45. }
  46. }
  47. func recovery() {
  48. if rec := recover(); rec != nil {
  49. log.Printf("Panic Panic occur")
  50. if err, ok := rec.(error); ok {
  51. log.Printf("PanicRecover Unhandled error: %v\n stack:%v", err.Error(), cast.ToString(debug.Stack()))
  52. } else {
  53. log.Printf("PanicRecover Panic: %v\n stack:%v", rec, cast.ToString(debug.Stack()))
  54. }
  55. }
  56. }