forked from TrueCloudLab/frostfs-node
[#2272] morph: Do not subscribe to events without listening
It led to a neo-go dead-lock in the `subscriber` component. Subscribing to notifications is the same RPC as any others, so it could also be blocked forever if no async listening (reading the notification channel) routine exists. If a number of subscriptions is big enough (or a caller is lucky enough) subscribing loop might have not finished subscribing before the first notification is received and then: subscribing RPC is blocked by received notification (non)handling and listening notifications routine is blocked by not finished subscription loop. That commit starts listening notification channel _before_ any subscription actions. Signed-off-by: Pavel Karpy <p.karpy@yadro.com>
This commit is contained in:
parent
2bdf7126b8
commit
a69c6d1ec9
3 changed files with 69 additions and 61 deletions
|
@ -17,12 +17,21 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
NotificationChannels struct {
|
||||
BlockCh <-chan *block.Block
|
||||
NotificationsCh <-chan *state.ContainedNotificationEvent
|
||||
NotaryRequestsCh <-chan *result.NotaryRequestEvent
|
||||
}
|
||||
|
||||
// Subscriber is an interface of the NotificationEvent listener.
|
||||
Subscriber interface {
|
||||
SubscribeForNotification(...util.Uint160) (<-chan *state.ContainedNotificationEvent, error)
|
||||
SubscribeForNotification(...util.Uint160) error
|
||||
UnsubscribeForNotification()
|
||||
BlockNotifications() (<-chan *block.Block, error)
|
||||
SubscribeForNotaryRequests(mainTXSigner util.Uint160) (<-chan *result.NotaryRequestEvent, error)
|
||||
BlockNotifications() error
|
||||
SubscribeForNotaryRequests(mainTXSigner util.Uint160) error
|
||||
|
||||
NotificationChannels() NotificationChannels
|
||||
|
||||
Close()
|
||||
}
|
||||
|
||||
|
@ -46,6 +55,14 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
func (s *subscriber) NotificationChannels() NotificationChannels {
|
||||
return NotificationChannels{
|
||||
BlockCh: s.blockChan,
|
||||
NotificationsCh: s.notifyChan,
|
||||
NotaryRequestsCh: s.notaryChan,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
errNilParams = errors.New("chain/subscriber: config was not provided to the constructor")
|
||||
|
||||
|
@ -54,7 +71,7 @@ var (
|
|||
errNilClient = errors.New("chain/subscriber: client was not provided to the constructor")
|
||||
)
|
||||
|
||||
func (s *subscriber) SubscribeForNotification(contracts ...util.Uint160) (<-chan *state.ContainedNotificationEvent, error) {
|
||||
func (s *subscriber) SubscribeForNotification(contracts ...util.Uint160) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
|
@ -69,14 +86,14 @@ func (s *subscriber) SubscribeForNotification(contracts ...util.Uint160) (<-chan
|
|||
_ = s.client.UnsubscribeContract(hash)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// save notification id
|
||||
notifyIDs[contracts[i]] = struct{}{}
|
||||
}
|
||||
|
||||
return s.notifyChan, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *subscriber) UnsubscribeForNotification() {
|
||||
|
@ -91,20 +108,20 @@ func (s *subscriber) Close() {
|
|||
s.client.Close()
|
||||
}
|
||||
|
||||
func (s *subscriber) BlockNotifications() (<-chan *block.Block, error) {
|
||||
func (s *subscriber) BlockNotifications() error {
|
||||
if err := s.client.SubscribeForNewBlocks(); err != nil {
|
||||
return nil, fmt.Errorf("could not subscribe for new block events: %w", err)
|
||||
return fmt.Errorf("could not subscribe for new block events: %w", err)
|
||||
}
|
||||
|
||||
return s.blockChan, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *subscriber) SubscribeForNotaryRequests(mainTXSigner util.Uint160) (<-chan *result.NotaryRequestEvent, error) {
|
||||
func (s *subscriber) SubscribeForNotaryRequests(mainTXSigner util.Uint160) error {
|
||||
if err := s.client.SubscribeForNotaryRequests(mainTXSigner); err != nil {
|
||||
return nil, fmt.Errorf("could not subscribe for notary request events: %w", err)
|
||||
return fmt.Errorf("could not subscribe for notary request events: %w", err)
|
||||
}
|
||||
|
||||
return s.notaryChan, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *subscriber) routeNotifications(ctx context.Context) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue