Skip to content

Commit f07f57d

Browse files
fix: synchronize access to lastPingTime in ticker struct (#99)
* fix: Synchronize access to lastPingTime in Ticker struct * fix: Synchronize access to lastPingTime in Ticker struct second pass * updated lasPingTime visibility, gitignored .vscode/settings.json * update: updated as specified
1 parent 1eb9eba commit f07f57d

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.chglog
2-
.env
2+
.env
3+
.vscode

ticker/ticker.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"math"
1010
"net/url"
1111
"sync"
12+
"sync/atomic"
1213
"time"
1314

1415
"github.com/gorilla/websocket"
@@ -28,7 +29,7 @@ type Ticker struct {
2829

2930
url url.URL
3031
callbacks callbacks
31-
lastPingTime time.Time
32+
lastPingTime atomicTime
3233
autoReconnect bool
3334
reconnectMaxRetries int
3435
reconnectMaxDelay time.Duration
@@ -41,6 +42,22 @@ type Ticker struct {
4142
cancel context.CancelFunc
4243
}
4344

45+
// atomicTime is wrapper over time.Time to safely access
46+
// an updating timestamp concurrently.
47+
type atomicTime struct {
48+
v atomic.Value
49+
}
50+
51+
// Get returns the current timestamp.
52+
func (b *atomicTime) Get() time.Time {
53+
return b.v.Load().(time.Time)
54+
}
55+
56+
// Set sets the current timestamp.
57+
func (b *atomicTime) Set(value time.Time) {
58+
b.v.Store(value)
59+
}
60+
4461
// callbacks represents callbacks available in ticker.
4562
type callbacks struct {
4663
onTick func(models.Tick)
@@ -311,7 +328,7 @@ func (t *Ticker) ServeWithContext(ctx context.Context) {
311328
t.reconnectAttempt = 0
312329

313330
// Set current time as last ping time
314-
t.lastPingTime = time.Now()
331+
t.lastPingTime.Set(time.Now())
315332

316333
// Set on close handler
317334
t.Conn.SetCloseHandler(t.handleClose)
@@ -339,6 +356,7 @@ func (t *Ticker) handleClose(code int, reason string) error {
339356
return nil
340357
}
341358

359+
342360
// Trigger callback methods
343361
func (t *Ticker) triggerError(err error) {
344362
if t.callbacks.onError != nil {
@@ -370,6 +388,7 @@ func (t *Ticker) triggerNoReconnect(attempt int) {
370388
}
371389
}
372390

391+
373392
func (t *Ticker) triggerMessage(messageType int, message []byte) {
374393
if t.callbacks.onMessage != nil {
375394
t.callbacks.onMessage(messageType, message)
@@ -401,7 +420,7 @@ func (t *Ticker) checkConnection(ctx context.Context, wg *sync.WaitGroup) {
401420

402421
// If last ping time is greater then timeout interval then close the
403422
// existing connection and reconnect
404-
if time.Since(t.lastPingTime) > dataTimeoutInterval {
423+
if time.Since(t.lastPingTime.Get()) > dataTimeoutInterval {
405424
// Close the current connection without waiting for close frame
406425
if t.Conn != nil {
407426
t.Conn.Close()
@@ -431,7 +450,7 @@ func (t *Ticker) readMessage(ctx context.Context, wg *sync.WaitGroup) {
431450
}
432451

433452
// Update last ping time to check for connection
434-
t.lastPingTime = time.Now()
453+
t.lastPingTime.Set(time.Now())
435454

436455
// Trigger message.
437456
t.triggerMessage(mType, msg)

0 commit comments

Comments
 (0)