Repository navigation
Conversation
fabwa
requested review from
End-rey,
carpawell,
cthulhu-rider and
roman-khimov
as code owners
November 10, 2026 17:25
fabwa
pushed a commit
to fabwa/neofs-node
that referenced
this pull request
Nov 10, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Fabian Wahle <fabian@nash.io>
4 tasks done
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #4299 +/- ##
==========================================
+ Coverage 32.70% 32.83% +0.12%
==========================================
Files 673 673
Lines 41698 41697 -1
==========================================
+ Hits 13638 13691 +53
+ Misses 28060 28006 -54 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The chain keeps delivering until SideChain.Stop, which runs as a node closer, while the service stops as soon as the node context is done - so the consumer tore down first and the chain kept writing into its channels. The service now runs until that closer stops it, after the chain, which also keeps someone draining the subscriptions while the chain shuts down. The two chain-fed channels are no longer closed either: neo-go's Close waits for its Run loop, not for the goroutine dispatching to subscribers, so a consumer can never tell that those sends have ceased. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Fabian Wahle <fabian@nash.io>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Fabian Wahle <fabian@nash.io>
fabwa
force-pushed
the
fix/meta-chain-shutdown-order
branch
from
November 10, 2026 19:35
fe013f1 to
0b95959
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #4283, which tried to solve this inside
Meta.Runby unsubscribing. That deadlocks, and as @carpawell put it there, the ordering "is hard to say inside this Meta service" — so this does it incmd/neofs-node, where both lifetimes are owned.Problem
SideChain.Stopis what actually takes the chain down (core.Close), and it is registered as a node closer. Closers run inshutdown(), afterwait()has already cancelled the node context — and the metadata service, like every other worker, stops the moment that context is done. So on every shutdown the consumer tears down first and the still-running chain keeps writing into the channels it was handed, which is wheresend on closed channelcomes from.Nothing drains those subscriptions in that window either. If a buffer fills, the chain's dispatcher blocks, the next
AddBlockholdsaddLockwaiting for it, andcore.Close— i.e. the closer itself — hangs with it, as @End-rey pointed out on #4283.Fix
The service now runs until the closer stops it, after the chain:
so the order is: chain stops delivering → service stops reading →
c.wg.Wait()collects it. The service keeps draining whileStopruns, so the dispatcher never blocks andcore.Closecannot wedge onaddLock. Its context is deliberately not the node's; that is the one deviation from the other workers and the comment says why.The two chain-fed channels are no longer closed.
Blockchain.CloseclosesstopChand waits onrunToExitCh, which is theRunloop only —notificationDispatcherobserves the samestopChbut nothing waits for it, and its sends sit outside itsselect. So there is no point at which a consumer can know the sends have stopped, whatever the ordering.m.taskQueueis still closed: its only writer isnotifyReceived, called fromnotificationHandler, whichRundoes wait on.Test plan
TestMeta_Run_DoesNotCloseChainFedChannelsfeeds both subscriptions from goroutinesRundoes not wait on, as the real dispatcher does, and fails withsend on closed channelif either close is restored — confirmed over-count=3 -race.-racegreen onpkg/services/metaandcmd/neofs-node, including-shuffle=1794309779113128012(the seed from meta: unsubscribe from the chain before closing its delivery channels #4283's metrics-registry report).golangci-lintwith the shared config,go build ./...andgo vet ./...clean.cfgand a real chain, andcmd/neofs-nodehas no harness for either.🤖 Generated with Claude Code