forked from TrueCloudLab/frostfs-node
[#337] morph: Move subscription logic to subscriber
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
a5f118a987
commit
35fdf6f315
5 changed files with 258 additions and 507 deletions
|
@ -6,11 +6,6 @@ import (
|
|||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -34,7 +29,8 @@ func (e *endpoints) init(ee []Endpoint) {
|
|||
e.list = ee
|
||||
}
|
||||
|
||||
func (c *Client) switchRPC(ctx context.Context) bool {
|
||||
// SwitchRPC performs reconnection and returns true if it was successful.
|
||||
func (c *Client) SwitchRPC(ctx context.Context) bool {
|
||||
c.switchLock.Lock()
|
||||
defer c.switchLock.Unlock()
|
||||
|
||||
|
@ -58,20 +54,8 @@ func (c *Client) switchRPC(ctx context.Context) bool {
|
|||
c.logger.Info(logs.ClientConnectionToTheNewRPCNodeHasBeenEstablished,
|
||||
zap.String("endpoint", newEndpoint))
|
||||
|
||||
subs, ok := c.restoreSubscriptions(ctx, cli, newEndpoint, false)
|
||||
if !ok {
|
||||
// new WS client does not allow
|
||||
// restoring subscription, client
|
||||
// could not work correctly =>
|
||||
// closing connection to RPC node
|
||||
// to switch to another one
|
||||
cli.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
c.client = cli
|
||||
c.setActor(act)
|
||||
c.subsInfo = subs
|
||||
|
||||
if c.cfg.switchInterval != 0 && !c.switchIsActive.Load() &&
|
||||
c.endpoints.list[c.endpoints.curr].Priority != c.endpoints.list[0].Priority {
|
||||
|
@ -82,97 +66,21 @@ func (c *Client) switchRPC(ctx context.Context) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
c.inactive = true
|
||||
|
||||
if c.cfg.inactiveModeCb != nil {
|
||||
c.cfg.inactiveModeCb()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Client) notificationLoop(ctx context.Context) {
|
||||
var e any
|
||||
var ok bool
|
||||
|
||||
for {
|
||||
c.switchLock.RLock()
|
||||
bChan := c.blockRcv
|
||||
nChan := c.notificationRcv
|
||||
nrChan := c.notaryReqRcv
|
||||
c.switchLock.RUnlock()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_ = c.UnsubscribeAll()
|
||||
c.close()
|
||||
|
||||
return
|
||||
case <-c.closeChan:
|
||||
_ = c.UnsubscribeAll()
|
||||
c.close()
|
||||
|
||||
return
|
||||
case e, ok = <-bChan:
|
||||
case e, ok = <-nChan:
|
||||
case e, ok = <-nrChan:
|
||||
}
|
||||
|
||||
if ok {
|
||||
c.routeEvent(ctx, e)
|
||||
continue
|
||||
}
|
||||
|
||||
if !c.reconnect(ctx) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) routeEvent(ctx context.Context, e any) {
|
||||
typedNotification := rpcclient.Notification{Value: e}
|
||||
|
||||
switch e.(type) {
|
||||
case *block.Block:
|
||||
typedNotification.Type = neorpc.BlockEventID
|
||||
case *state.ContainedNotificationEvent:
|
||||
typedNotification.Type = neorpc.NotificationEventID
|
||||
case *result.NotaryRequestEvent:
|
||||
typedNotification.Type = neorpc.NotaryRequestEventID
|
||||
}
|
||||
|
||||
func (c *Client) closeWaiter(ctx context.Context) {
|
||||
select {
|
||||
case c.notifications <- typedNotification:
|
||||
case <-ctx.Done():
|
||||
_ = c.UnsubscribeAll()
|
||||
c.close()
|
||||
case <-c.closeChan:
|
||||
_ = c.UnsubscribeAll()
|
||||
c.close()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) reconnect(ctx context.Context) bool {
|
||||
if closeErr := c.client.GetError(); closeErr != nil {
|
||||
c.logger.Warn(logs.ClientSwitchingToTheNextRPCNode,
|
||||
zap.String("reason", closeErr.Error()),
|
||||
)
|
||||
} else {
|
||||
// neo-go client was closed by calling `Close`
|
||||
// method, that happens only when a client has
|
||||
// switched to the more prioritized RPC
|
||||
return true
|
||||
}
|
||||
|
||||
if !c.switchRPC(ctx) {
|
||||
c.logger.Error(logs.ClientCouldNotEstablishConnectionToAnyRPCNode)
|
||||
|
||||
// could not connect to all endpoints =>
|
||||
// switch client to inactive mode
|
||||
c.inactiveMode()
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO(@carpawell): call here some callback retrieved in constructor
|
||||
// of the client to allow checking chain state since during switch
|
||||
// process some notification could be lost
|
||||
|
||||
return true
|
||||
_ = c.UnsubscribeAll()
|
||||
c.close()
|
||||
}
|
||||
|
||||
func (c *Client) switchToMostPrioritized(ctx context.Context) {
|
||||
|
@ -218,36 +126,28 @@ mainLoop:
|
|||
continue
|
||||
}
|
||||
|
||||
if subs, ok := c.restoreSubscriptions(ctx, cli, tryE, true); ok {
|
||||
c.switchLock.Lock()
|
||||
|
||||
// higher priority node could have been
|
||||
// connected in the other goroutine
|
||||
if e.Priority >= c.endpoints.list[c.endpoints.curr].Priority {
|
||||
cli.Close()
|
||||
c.switchLock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
c.client.Close()
|
||||
c.cache.invalidate()
|
||||
c.client = cli
|
||||
c.setActor(act)
|
||||
c.subsInfo = subs
|
||||
c.endpoints.curr = i
|
||||
c.switchLock.Lock()
|
||||
|
||||
// higher priority node could have been
|
||||
// connected in the other goroutine
|
||||
if e.Priority >= c.endpoints.list[c.endpoints.curr].Priority {
|
||||
cli.Close()
|
||||
c.switchLock.Unlock()
|
||||
|
||||
c.logger.Info(logs.ClientSwitchedToTheHigherPriorityRPC,
|
||||
zap.String("endpoint", tryE))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
c.logger.Warn(logs.ClientCouldNotRestoreSideChainSubscriptionsUsingNode,
|
||||
zap.String("endpoint", tryE),
|
||||
zap.Error(err),
|
||||
)
|
||||
c.client.Close()
|
||||
c.cache.invalidate()
|
||||
c.client = cli
|
||||
c.setActor(act)
|
||||
c.endpoints.curr = i
|
||||
|
||||
c.switchLock.Unlock()
|
||||
|
||||
c.logger.Info(logs.ClientSwitchedToTheHigherPriorityRPC,
|
||||
zap.String("endpoint", tryE))
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -255,6 +155,7 @@ mainLoop:
|
|||
|
||||
// close closes notification channel and wrapped WS client.
|
||||
func (c *Client) close() {
|
||||
close(c.notifications)
|
||||
c.switchLock.RLock()
|
||||
defer c.switchLock.RUnlock()
|
||||
c.client.Close()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue