From 95ee9058614bf147ea04ec979bafe373d266120d Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Tue, 7 Feb 2023 19:35:15 +0300 Subject: [PATCH] [#2244] node: Fix subscriptions lock Subscribing without async listening could lead to a dead-lock in the `neo-go` client. Signed-off-by: Pavel Karpy --- CHANGELOG.md | 1 + pkg/morph/client/notifications.go | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb8ad51d8d..289725febf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ Changelog for FrostFS Node - Possible deadlock in write-cache (#2239) - Fix `*_req_count` and `*_req_count_success` metric values (#2241) - Storage ID update by write-cache (#2244) +- `neo-go` client deadlock on subscription restoration (#2244) ### Removed ### Updated diff --git a/pkg/morph/client/notifications.go b/pkg/morph/client/notifications.go index 63e5a5c8aa..2afeebb832 100644 --- a/pkg/morph/client/notifications.go +++ b/pkg/morph/client/notifications.go @@ -211,6 +211,29 @@ func (c *Client) restoreSubscriptions(cli *rpcclient.WSClient, endpoint string) id string ) + stopCh := make(chan struct{}) + defer close(stopCh) + + // neo-go WS client says to _always_ read notifications + // from its channel. Subscribing to any notification + // while not reading them in another goroutine may + // lead to a dead-lock, thus that async side notification + // listening while restoring subscriptions + go func() { + for { + select { + case <-stopCh: + return + case n, ok := <-cli.Notifications: + if !ok { + return + } + + c.notifications <- n + } + } + }() + // new block events restoration if c.subscribedToNewBlocks { _, err = cli.SubscribeForNewBlocks(nil)