Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PLAT-742] Adds ReconnectCallback to ws go-client #440

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Polygon Go Client
![Coverage](https://img.shields.io/badge/Coverage-76.7%25-brightgreen)
![Coverage](https://img.shields.io/badge/Coverage-77.4%25-brightgreen)

<!-- todo: add a codecov badge -->
<!-- todo: figure out a way to show all build statuses -->
Expand Down
6 changes: 6 additions & 0 deletions websocket/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ type Config struct {
// If this flag is `true`, it's up to the caller to handle all message types including auth and subscription responses.
BypassRawDataRouting bool

// ReconnectCallback is a callback that is triggered on automatic reconnects by the websocket client.
// This can be useful for implementing additional logic around reconnect paths e.g. logging, metrics
// or managing the connection. The callback function takes as input an error type which will be non-nil
// if the reconnect attempt has failed and is being retried, and will be nil on reconnect success.
ReconnectCallback func(error)

// Log is an optional logger. Any logger implementation can be used as long as it
// implements the basic Logger interface. Omitting this will disable client logging.
Log Logger
Expand Down
12 changes: 11 additions & 1 deletion websocket/polygon.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ type Client struct {
output chan any
err chan error

log Logger
reconnectCallback func(error)
log Logger
}

// New creates a client for the Polygon WebSocket API.
Expand All @@ -70,6 +71,7 @@ func New(config Config) (*Client, error) {
output: make(chan any, 100000),
err: make(chan error),
log: config.Log,
reconnectCallback: config.ReconnectCallback,
}

uri, err := url.Parse(string(c.feed))
Expand Down Expand Up @@ -246,13 +248,21 @@ func (c *Client) reconnect() {

notify := func(err error, _ time.Duration) {
c.log.Errorf(err.Error())
if c.reconnectCallback != nil {
c.reconnectCallback(err)
}
}
err := backoff.RetryNotify(c.connect(true), c.backoff, notify)
if err != nil {
err = fmt.Errorf("error reconnecting: %w: closing connection", err)
c.log.Errorf(err.Error())
c.close(false)
c.err <- err
} else {
// Callback on success.
if c.reconnectCallback != nil {
c.reconnectCallback(nil)
}
}
}

Expand Down
29 changes: 29 additions & 0 deletions websocket/polygon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,32 @@ func TestConnectRetryFailure(t *testing.T) {
assert.NotNil(t, err)
c.Close()
}

func TestReconnectCallback(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(connect))
defer s.Close()

reconnectCallbackCount := 0
log := logrus.New()
log.SetLevel(logrus.DebugLevel)
u := "ws" + strings.TrimPrefix(s.URL, "http")
var retries uint64 = 0
c, err := New(Config{
APIKey: "good",
Feed: Feed(u),
Market: Market(""),
Log: log,
MaxRetries: &retries,
ReconnectCallback: func(err error) {
assert.Nil(t, err)
reconnectCallbackCount++
},
})
assert.NotNil(t, c)
assert.Nil(t, err)
err = c.Connect()
assert.Nil(t, err)
c.reconnect()
c.Close()
assert.Equal(t, 1, reconnectCallbackCount)
}
Loading