Dawn's Blogs

分享技术 记录成长

0%

Gin基本使用 (6) 自定义HTTP配置和运行多个服务

自定义 HTTP 配置

直接使用 http.ListenAndServe()

1
2
3
4
func main() {
router := gin.Default()
http.ListenAndServe(":8080", router)
}

或者首先定义 http.Server,再调用 http.Server.ListenAndServe()

1
2
3
4
5
6
7
8
9
10
11
12
func main() {
router := gin.Default()

s := &http.Server{
Addr: ":8080",
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}

运行多个服务

errgroup 库

在 Go 语言中,我们可以使用 errgroup 库处理 goroutine 中的错误。

基本使用

使用 errgroup 库的 Go() 方法启动两个 goroutine,分别模拟错误 goroutine 和正常 goroutine

然后,使用 errgroup 库的 Wait() 方法判断是否有 goroutine 返回错误信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func main() {
eg := errgroup.Group{}
eg.Go(func() error {
fmt.Println("go1")
return nil
})

eg.Go(func() error {
fmt.Println("go2")
err := errors.New("go2 err")
return err
})

err := eg.Wait()
if err != nil {
fmt.Println("err =", err)
}
}

附加 cancel 功能

使用 errgroup 库的 WithContext() 函数,可以附加 cancel 功能。

在第一个使用 Go() 方法启动的协程函数中,使用 select ... case ... default 监听其他协程是否返回错误并做出相应的逻辑处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func main() {
eg, ctx := errgroup.WithContext(context.Background())

eg.Go(func() error {
time.Sleep(1 * time.Second)
select {
case <-ctx.Done():
fmt.Println("go1 cancel, err = ", ctx.Err())
default:
fmt.Println("go1 run")
}
return nil
})

eg.Go(func() error {
err := errors.New("go2 err")
return err
})

err := eg.Wait()
if err != nil {
fmt.Println("err =", err)
}
}

限制并发数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func main() {
eg := errgroup.Group{}
// 限制并发数量
eg.SetLimit(2)

// 用 TryGo 代替 Go
eg.TryGo(func() error {
fmt.Println("go1 run")
return nil
})
eg.TryGo(func() error {
err := errors.New("go2 err")
return err
})
eg.TryGo(func() error {
fmt.Println("go3 run")
return nil
})

err := eg.Wait()
if err != nil {
fmt.Println("err =", err)
}
}

利用 errgroup 运行多个服务

可以利用 errgroup 库运行多个服务,具体的方法是:

  • 定义多个 http.Server,每一个 http.Server 都运行一个服务。
  • 利用 errgroup.Go 函数运行每一个服务,即在每一个 errgroup.Go 内部都调用 ListenAndServe。
  • 使用 errgroup 库的 Wait 方法判断是否有服务返回错误信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package main

import (
"log"
"net/http"
"time"

"github.com/gin-gonic/gin"
"golang.org/x/sync/errgroup"
)

var (
g errgroup.Group
)

func router01() http.Handler {
e := gin.New()
e.Use(gin.Recovery())
e.GET("/", func(c *gin.Context) {
c.JSON(
http.StatusOK,
gin.H{
"code": http.StatusOK,
"error": "Welcome server 01",
},
)
})

return e
}

func router02() http.Handler {
e := gin.New()
e.Use(gin.Recovery())
e.GET("/", func(c *gin.Context) {
c.JSON(
http.StatusOK,
gin.H{
"code": http.StatusOK,
"error": "Welcome server 02",
},
)
})

return e
}

func main() {
server01 := &http.Server{
Addr: ":8080",
Handler: router01(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}

server02 := &http.Server{
Addr: ":8081",
Handler: router02(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}

g.Go(func() error {
return server01.ListenAndServe()
})

g.Go(func() error {
return server02.ListenAndServe()
})

if err := g.Wait(); err != nil {
log.Fatal(err)
}
}