Skip to content

Commit 1adf90e

Browse files
committed
experimental fix and test to reproduce panic on concurrent disconnect and close
1 parent 653f7dd commit 1adf90e

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

client.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,8 +769,11 @@ func (c *Client) reader(t transport, disconnectCh chan struct{}) {
769769
}
770770

771771
func (c *Client) runHandlerSync(fn func()) {
772-
waitCh := make(chan struct{})
773772
c.mu.RLock()
773+
if c.cbQueue == nil {
774+
return
775+
}
776+
waitCh := make(chan struct{})
774777
c.cbQueue.push(func(delay time.Duration) {
775778
defer close(waitCh)
776779
fn()
@@ -780,9 +783,14 @@ func (c *Client) runHandlerSync(fn func()) {
780783
}
781784

782785
func (c *Client) runHandlerAsync(fn func()) {
786+
c.mu.RLock()
787+
if c.cbQueue == nil {
788+
return
789+
}
783790
c.cbQueue.push(func(delay time.Duration) {
784791
fn()
785792
})
793+
c.mu.RUnlock()
786794
}
787795

788796
func (c *Client) handle(reply *protocol.Reply) {

client_test.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,32 @@ func TestSubscription_Unsubscribe(t *testing.T) {
334334
select {
335335
case <-unsubscribedCh:
336336
case <-time.After(3 * time.Second):
337-
t.Errorf("timeout waiting for subscribe")
337+
t.Errorf("timeout waiting for unsubscribe")
338+
}
339+
}
340+
341+
func TestConcurrentCloseDisconnect(t *testing.T) {
342+
// Race condtition probability between close and disconnect is small,
343+
// so doing a lot of iterations to reproduce reliably.
344+
for i := 0; i < 10000; i++ {
345+
client := NewJsonClient("ws://localhost:8000/connection/websocket?cf_protocol_version=v2", Config{})
346+
client.OnConnecting(func(ConnectingEvent) {})
347+
if err := client.Connect(); err != nil {
348+
t.Fatalf("failed to connect: %v", err)
349+
}
350+
sub, err := client.NewSubscription("thechannel", SubscriptionConfig{})
351+
if err != nil {
352+
t.Fatalf("failed to subscribe: %v", err)
353+
}
354+
sub.OnUnsubscribed(func(UnsubscribedEvent) {})
355+
sub.OnSubscribing(func(SubscribingEvent) {})
356+
sub.Subscribe()
357+
go client.Close()
358+
client.handleDisconnect(&disconnect{
359+
Code: connectingTransportClosed,
360+
Reason: "transport closed",
361+
Reconnect: false,
362+
})
338363
}
339364
}
340365

0 commit comments

Comments
 (0)