Skip to content

Commit

Permalink
failover: add method to manually reconnect
Browse files Browse the repository at this point in the history
When all servers are down, a retry only happens after the retry
timeout. We want to be able to manually trigger reconnecting earlier
than that.

When the BitBoxApp iOS app goes into background, it kills TCP
connections shortly after. We want to be able to trigger a reconnecct
as soon as the iOS app comes to the foreground again.
  • Loading branch information
benma committed Sep 30, 2024
1 parent 0d604ac commit 12964f9
Showing 1 changed file with 24 additions and 1 deletion.
25 changes: 24 additions & 1 deletion failover/failover.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ type Failover[C Client] struct {
enableRetry bool
subscriptions []func(client C, currentClientCounter int)

manualReconnect chan struct{}

closed bool
closedMu sync.RWMutex
}
Expand All @@ -145,6 +147,7 @@ func New[C Client](opts *Options[C]) *Failover[C] {
opts: opts,
startServerIndex: startServerIndex,
currentServerIndex: startServerIndex,
manualReconnect: make(chan struct{}),
}
}

Expand All @@ -157,7 +160,17 @@ func (f *Failover[C]) establishConnection() error {
if f.opts.OnRetry != nil {
go f.opts.OnRetry(f.lastErr)
}
time.Sleep(retryTimeout)

// Drain the manualReconnect channel to avoid stale reconnect signals
select {
case <-f.manualReconnect:
default:
}
// Wait for retry timeout or manual reconnect
select {
case <-time.After(retryTimeout):
case <-f.manualReconnect:
}
}
f.enableRetry = true

Expand Down Expand Up @@ -370,6 +383,16 @@ func (f *Failover[C]) isClosed() bool {
return f.closed
}

// ManualReconnect triggers a manual reconnect, non-blocking.
// This re-tries connecting immediately without waiting for the retry timeout.
// We we are not currently disconnected, this is a no-op.
func (f *Failover[C]) ManualReconnect() {
select {
case f.manualReconnect <- struct{}{}:
default:
}
}

// Close closes the failover client and closes the current client, resulting in `ErrClosed` in all
// future `Call` and `Subscribe` calls. It also calls `Close()` on the currently active client if
// one exists.
Expand Down

0 comments on commit 12964f9

Please sign in to comment.