Skip to content

Commit

Permalink
morph: support reloading morph endpoints with sighup (#2998)
Browse files Browse the repository at this point in the history
Closes #1871.
  • Loading branch information
carpawell authored Nov 7, 2024
2 parents ecaffa0 + 51dacc9 commit 007e992
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ attribute, which is used for container domain name in NNS contracts (#2954)
- `--disable-auto-gen-tag` flag for gendoc command (#2983)
- Docs files for cli commands to the `docs/cli-commands` folder (#2983)
- `logger.encoding` config option (#2999)
- Reloading morph endpoints with SIGHUP (#2998)

### Fixed
- Do not search for tombstones when handling their expiration, use local indexes instead (#2929)
Expand Down
4 changes: 4 additions & 0 deletions cmd/neofs-node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,10 @@ func (c *cfg) configWatcher(ctx context.Context) {
continue
}

// Morph

c.cli.Reload(client.WithEndpoints(c.morph.endpoints))

c.log.Info("configuration has been reloaded successfully")
case <-ctx.Done():
return
Expand Down
8 changes: 6 additions & 2 deletions docs/sighup.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ Available for reconfiguration fields:

```yml
head_timeout:
cache_size:
cache_time:
replication_cooldown:
object_batch_size:
max_workers:
Expand All @@ -34,3 +32,9 @@ comparing paths from `shard.blobstor` section. After this we have 3 sets:
| Changed section | Actions |
|-----------------|----------------------------------------------------------------------------------------------------------------------|
| `path` | If `path` is different, metabase is closed and opened with a new path. All other configuration will also be updated. |

### Morph

| Changed section | Actions |
|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `endpoints` | Updates N3 endpoints.<br/>If new `endpoints` do not contain the endpoint client is connected to, it will reconnect to another endpoint from the new list. Node service can be interrupted in this case. |
2 changes: 0 additions & 2 deletions pkg/morph/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ type Client struct {

cfg cfg

endpoints []string

subs subscriptions

// channel for internal stop
Expand Down
5 changes: 3 additions & 2 deletions pkg/morph/client/constructor.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ type cfg struct {
autoSidechainScope bool
signer *transaction.Signer

endpoints []string
endpointsLock *sync.RWMutex
endpoints []string

singleCli *rpcclient.WSClient // neo-go client for single client mode

Expand All @@ -63,6 +64,7 @@ func defaultConfig() *cfg {
signer: &transaction.Signer{
Scopes: transaction.CalledByEntry,
},
endpointsLock: &sync.RWMutex{},
reconnectionDelay: 5 * time.Second,
reconnectionRetries: 5,
}
Expand Down Expand Up @@ -139,7 +141,6 @@ func New(key *keys.PrivateKey, opts ...Option) (*Client, error) {
return nil, errors.New("no endpoints were provided")
}

cli.endpoints = cfg.endpoints
conn = cli.connEndpoints()
if conn == nil {
err = errors.New("could not establish Neo RPC connection")
Expand Down
11 changes: 4 additions & 7 deletions pkg/morph/client/multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ import (
"go.uber.org/zap"
)

// Endpoint represents morph endpoint together with its priority.
type Endpoint struct {
Address string
Priority int
}

// SwitchRPC performs reconnection and returns new if it was successful.
func (c *Client) switchRPC() *connection {
var conn = c.conn.Swap(nil)
Expand Down Expand Up @@ -39,8 +33,11 @@ func (c *Client) switchRPC() *connection {
}

func (c *Client) connEndpoints() *connection {
c.cfg.endpointsLock.RLock()
defer c.cfg.endpointsLock.RUnlock()

// Iterate endpoints.
for _, e := range c.endpoints {
for _, e := range c.cfg.endpoints {
conn, err := c.newConnection(e)
if err != nil {
c.logger.Warn("could not establish connection to RPC node",
Expand Down
29 changes: 29 additions & 0 deletions pkg/morph/client/reload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package client

import "slices"

// Reload allows runtime reconfiguration for WithEndpoints parameter.
func (c *Client) Reload(opts ...Option) {
cfg := new(cfg)
for _, o := range opts {
o(cfg)
}

c.cfg.endpointsLock.Lock()

c.cfg.endpoints = cfg.endpoints

c.cfg.endpointsLock.Unlock()

conn := c.conn.Load()
if conn == nil {
return
}

// Close current connection and attempt to reconnect, if there is no endpoint
// in the config to which the client is connected.
// Node service can be interrupted in this case.
if slices.Contains(cfg.endpoints, conn.client.Endpoint()) {
conn.client.Close()
}
}

0 comments on commit 007e992

Please sign in to comment.