Webhub race condition (#9863)
* fix webconn close semantics Avoid race conditions in WebConn on shutdown by closing channels to guarantee all readers are notified. Wrap this with sync.Once to avoid closing the channel more than once. * web_hub_test.go * webhub: fix race condition on shutdown Ensure that if the webhub shuts down in the process of sending, the caller unblocks given that the webhub will no longer consume incoming events. * panic if app shutdown takes >30 seconds * simplify WebConn::Pump channel semantics too
Этот коммит содержится в:
коммит произвёл
Jesús Espino
родитель
1271908182
Коммит
f8ffd68060
@@ -5,6 +5,7 @@ package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -39,6 +40,7 @@ type WebConn struct {
|
||||
AllChannelMembers map[string]string
|
||||
LastAllChannelMembersTime int64
|
||||
Sequence int64
|
||||
closeOnce sync.Once
|
||||
endWritePump chan struct{}
|
||||
pumpFinished chan struct{}
|
||||
}
|
||||
@@ -59,8 +61,8 @@ func (a *App) NewWebConn(ws *websocket.Conn, session model.Session, t goi18n.Tra
|
||||
UserId: session.UserId,
|
||||
T: t,
|
||||
Locale: locale,
|
||||
endWritePump: make(chan struct{}, 2),
|
||||
pumpFinished: make(chan struct{}, 1),
|
||||
endWritePump: make(chan struct{}),
|
||||
pumpFinished: make(chan struct{}),
|
||||
}
|
||||
|
||||
wc.SetSession(&session)
|
||||
@@ -72,7 +74,9 @@ func (a *App) NewWebConn(ws *websocket.Conn, session model.Session, t goi18n.Tra
|
||||
|
||||
func (wc *WebConn) Close() {
|
||||
wc.WebSocket.Close()
|
||||
wc.endWritePump <- struct{}{}
|
||||
wc.closeOnce.Do(func() {
|
||||
close(wc.endWritePump)
|
||||
})
|
||||
<-wc.pumpFinished
|
||||
}
|
||||
|
||||
@@ -105,16 +109,18 @@ func (c *WebConn) SetSession(v *model.Session) {
|
||||
}
|
||||
|
||||
func (c *WebConn) Pump() {
|
||||
ch := make(chan struct{}, 1)
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
c.writePump()
|
||||
ch <- struct{}{}
|
||||
close(ch)
|
||||
}()
|
||||
c.readPump()
|
||||
c.endWritePump <- struct{}{}
|
||||
c.closeOnce.Do(func() {
|
||||
close(c.endWritePump)
|
||||
})
|
||||
<-ch
|
||||
c.App.HubUnregister(c)
|
||||
c.pumpFinished <- struct{}{}
|
||||
close(c.pumpFinished)
|
||||
}
|
||||
|
||||
func (c *WebConn) readPump() {
|
||||
|
||||
Ссылка в новой задаче
Block a user