首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >websocket优雅关闭

websocket优雅关闭
EN

Stack Overflow用户
提问于 2021-09-30 09:33:32
回答 1查看 468关注 0票数 0

我有一个websocket服务器。我为他写了一个测试,测试他优雅地关机的能力。创建了5个连接,每个连接发送5个请求。一段时间后,关机就开始了。所有25项要求都必须得到满足。如果我关闭了exit通道,那么测试就不能正常工作。

代码语言:javascript
复制
    time.AfterFunc(50*time.Millisecond, func() {
        close(exit)
        close(done)
    })

如果我只调用s.shutdown函数,那么一切都没问题。

代码语言:javascript
复制
    time.AfterFunc(50*time.Millisecond, func() {
        require.Nil(t, s.Shutdown())
        close(done)
    })

我的测验

代码语言:javascript
复制
func TestServer_GracefulShutdown(t *testing.T) {
    done := make(chan struct{})
    exit := make(chan struct{})
    ctx := context.Background()

    finishedRequestCount := atomic.NewInt32(0)
    ln, err := net.Listen("tcp", "localhost:")
    require.Nil(t, err)

    handler := HandlerFunc(func(conn *websocket.Conn) {
        for {
            _, _, err := conn.ReadMessage()
            if err != nil {
                return
            }
            time.Sleep(100 * time.Millisecond)
            finishedRequestCount.Inc()
        }
    })
    s, err := makeServer(ctx, handler) // server create
    require.Nil(t, err)
    time.AfterFunc(50*time.Millisecond, func() {
        close(exit)
        close(done)
    })
    go func() {
        fmt.Printf("Running...")
        require.Nil(t, s.Run(ctx, exit, ln))
    }()
    for i := 0; i < connCount; i++ {
        go func() {
            err := clientRun(ln)
            require.Nil(t, err)
        }()
    }

    <-done

    assert.Equal(t, int32(totalCount), finishedRequestCount.Load())
}

我的跑步漏斗

代码语言:javascript
复制
func (s *Server) Run(ctx context.Context, exit <-chan struct{}, ln net.Listener) error {
    errs := make(chan error, 1)

    go func() {
        err := s.httpServer.Run(ctx, exit, ln)
        if err != nil {
            errs <- err
        }
    }()

    select {
    case <-ctx.Done():
        return s.Close()
    case <-exit:
        return s.Shutdown()
    case err := <-errs:
        return err
    }
}

我关机

代码语言:javascript
复制
func (s *Server) Shutdown() error {
    err := s.httpServer.Shutdown() // we close the possibility to connect to any conn
    s.wg.Wait()
    return err
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-09-30 10:34:18

如果执行以下代码,会发生什么情况?

代码语言:javascript
复制
close(exit)
close(done)

两个频道几乎同时关闭。第一个触发Shutdown函数,该函数等待优雅的关闭。但是第二个触发了对

代码语言:javascript
复制
assert.Equal(t, int32(totalCount), finishedRequestCount.Load())

它是在优雅的关机仍在运行或尚未启动时触发的。

如果直接执行关机函数,它将一直阻塞直到完成,只有这样,close(done)才会启动断言。这就是为什么这样做的原因:

代码语言:javascript
复制
require.Nil(t, s.Shutdown())
close(done)

您可以将close(done)移动到以下位置以使测试工作,同时使用exit通道关闭:

代码语言:javascript
复制
go func() {
    fmt.Printf("Running...")
    require.Nil(t, s.Run(ctx, exit, ln))
    close(done)
}()

这样,done将在执行Shutdown函数后关闭。

正如评论中所讨论的,我强烈建议使用上下文而不是通道来关闭。它们的复杂性在于隐藏着封闭的通道。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69389783

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档