Skip to content

Commit

Permalink
[ADDED] AllowCloseRetry option
Browse files Browse the repository at this point in the history
In PR #360, we changed the default behavior of connection Close()
in that if the library failed to sent the close protocol or received
its response, the Close() could be retried. In order to do that,
the underlying NATS connection would not be closed.

This has side-effects in that the NATS connection would be left
opened or possibly reconnect when an user would have previously
called Close(), not check error, and expect NATS connection to
be closed.

The introduction of this option allow the default behavior to
remain the same, and users that do want to be able to call Close()
again on a failed call will need to set this option when creating
the connection.

Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
  • Loading branch information
kozlovic committed Nov 17, 2021
1 parent 9937a12 commit f27faca
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 2 deletions.
32 changes: 31 additions & 1 deletion stan.go
Expand Up @@ -179,6 +179,21 @@ type Options struct {
// ConnectionLostCB specifies the handler to be invoked when the connection
// is permanently lost.
ConnectionLostCB ConnectionLostHandler

// AllowCloseRetry specifies that a failed connection Close() can be retried.
//
// By default, after the first call to Close(), the underlying NATS connection
// is closed (when owned by the library), regardless if the library gets a
// response from the server or not, and calling Close() again is a no-op.
// With AllowCloseRetry set to true, if the library fails to get a response
// from the close protocol, calling Close() again is possible and the library
// will try to resend the protocol. It means that the underlying NATS connection
// won't be closed until the library successfully gets a response from the server.
// This behavior can have side effects in that the underlying NATS connection
// may stay open (or reconnect) when otherwise it would have been closed after
// calling Close(). So AllowCloseRetry is disabled by default to maintain
// expected default behavior in regard with the underlying NATS connection state.
AllowCloseRetry bool
}

// GetDefaultOptions returns default configuration options for the client.
Expand Down Expand Up @@ -308,6 +323,15 @@ func SetConnectionLostHandler(handler ConnectionLostHandler) Option {
}
}

// AllowCloseRetry is an Option that allows a failed connection close to be retried.
// See option AllowCloseRetry for more information.
func AllowCloseRetry(allow bool) Option {
return func(o *Options) error {
o.AllowCloseRetry = allow
return nil
}
}

// A conn represents a bare connection to a stan cluster.
type conn struct {
sync.RWMutex
Expand Down Expand Up @@ -682,6 +706,12 @@ func (sc *conn) Close() error {
if !sc.closed {
sc.closed = true
sc.cleanupOnClose(ErrConnectionClosed)
if !sc.opts.AllowCloseRetry {
sc.fullyClosed = true
if sc.ncOwned {
defer sc.nc.Close()
}
}
}

req := &pb.CloseRequest{ClientID: sc.clientID}
Expand All @@ -700,7 +730,7 @@ func (sc *conn) Close() error {
}
// As long as we got a valid response, we consider the connection fully closed.
sc.fullyClosed = true
if sc.ncOwned {
if sc.ncOwned && sc.opts.AllowCloseRetry {
sc.nc.Close()
}
if cr.Error != "" {
Expand Down
5 changes: 4 additions & 1 deletion stan_test.go
Expand Up @@ -1012,7 +1012,10 @@ func TestConnCloseError(t *testing.T) {
s := RunServer(clusterName)
defer s.Shutdown()

sc := NewDefaultConnection(t)
sc, err := Connect(clusterName, clientName, AllowCloseRetry(true))
if err != nil {
t.Fatalf("Error on connect: %v", err)
}
defer sc.Close()

nc, err := nats.Connect(nats.DefaultURL)
Expand Down

0 comments on commit f27faca

Please sign in to comment.