@cryptotaxi247 / kubo / commits / d01246f11

feat(pinner): close pinner before repo on shutdown (#11296)

* feat(pinner): close pinner before repo on shutdown The pinner's streaming goroutines hold a reference to the backing datastore, and pebble panics on use after Close. Before this change the panic was recovered inside the pinner (see ipfs/boxo#1146) and the symptom was only a transient log trace on daemon exit, but the race remained. Register a new fx OnStop hook that calls pinner.Close before the repo (and therefore the datastore) closes. Close drains all in-flight stream goroutines, so the datastore is closed only after the pinner is fully quiesced. Bumps boxo to pick up Pinner.Close from ipfs/boxo#1150. Fixes https://github.com/ipfs/kubo/issues/11292 * chore(deps): bump boxo to ipfs/boxo#1150 (70ffcfa) * chore(deps): bump boxo to ipfs/boxo#1150 (75481f4) ipfs/boxo#1150 was reworked to use context fan-out instead of a done channel. Pinner.Close now cancels every admitted op and waits for them to return, broadening the shutdown contract from "drain streams" to "drain everything". Comments and changelog reworded to match. * chore(deps): bump boxo to latest main (b2b5d8a)

Marcin Rataj committed May 14, 2026 at 23:29 UTC d01246f11b809c87d66d37a869c834f671a8759b
8 files changed +32 -12
core/node/core.go
+21 -3
@@ -50,11 +50,19 @@ func BlockService(cfg *config.Config) func(lc fx.Lifecycle, bs blockstore.Blocks
50 }
51 }
52
53 -// Pinning creates new pinner which tells GC which blocks should be kept
54 -func Pinning(strategy string) func(bstore blockstore.Blockstore, ds format.DAGService, repo repo.Repo, prov DHTProvider) (pin.Pinner, error) {
53 +// Pinning builds the pinner that GC uses to decide which blocks to keep.
54 +//
55 +// An fx OnStop hook closes the pinner before the repo (and its
56 +// datastore). The order matters: in-flight pinner operations hold a
57 +// reference to the datastore, and some datastores (pebble) panic on
58 +// use after Close. Pinner.Close cancels those operations and waits
59 +// for them to return. See
60 +// [github.com/ipfs/boxo/pinning/pinner.Pinner.Close].
61 +func Pinning(strategy string) func(lc fx.Lifecycle, bstore blockstore.Blockstore, ds format.DAGService, repo repo.Repo, prov DHTProvider) (pin.Pinner, error) {
62 strategyFlag := config.MustParseProvideStrategy(strategy)
63
57 - return func(bstore blockstore.Blockstore,
64 + return func(lc fx.Lifecycle,
65 + bstore blockstore.Blockstore,
66 ds format.DAGService,
67 repo repo.Repo,
68 prov DHTProvider,
@@ -91,6 +99,16 @@ func Pinning(strategy string) func(bstore blockstore.Blockstore, ds format.DAGSe
99 return nil, err
100 }
101
102 + // fx runs OnStop hooks in reverse registration order. The
103 + // repo provider registers its close hook earlier (in
104 + // builder.go), so this hook runs first and the repo hook
105 + // runs after, without an explicit dependency between them.
106 + lc.Append(fx.Hook{
107 + OnStop: func(context.Context) error {
108 + return pinning.Close()
109 + },
110 + })
111 +
112 return pinning, nil
113 }
114 }
docs/changelogs/v0.42.md
+2
@@ -27,6 +27,8 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
27
28 The pinner now snapshots the index under the read lock and releases it before the reprovider starts, so pin operations are no longer blocked by the reprovide cycle. The default `Provide.Strategy=all` was not affected.
29
30 +Daemon shutdown is also cleaner under these strategies: the pinner now cancels and drains in-flight work before the datastore closes, so the transient `pebble: closed` panic trace on exit is gone.
31 +
32 #### 🚨 ERROR log for listeners blocked by `Swarm.AddrFilters` or `Addresses.NoAnnounce`
33
34 Kubo now logs an ERROR when an [`Addresses.Swarm`](https://github.com/ipfs/kubo/blob/master/docs/config.md#addressesswarm) listener is covered by a rule in [`Swarm.AddrFilters`](https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmaddrfilters) (Kubo will reject every incoming connection to it) or [`Addresses.NoAnnounce`](https://github.com/ipfs/kubo/blob/master/docs/config.md#addressesnoannounce) (Kubo will not advertise it to other peers). Each line names the listener, the matching rule, and the field to remove it from. This catches silent misconfigurations like a `/ip4/127.0.0.1/tcp/.../ws` listener behind a local reverse proxy that stops working once `/ip4/127.0.0.0/ipcidr/8` lands in `Swarm.AddrFilters` (for example via the [`server` profile](https://github.com/ipfs/kubo/blob/master/docs/config.md#server-profile)). See the [reverse-proxy override row](https://github.com/ipfs/kubo/blob/master/docs/config.md#overriding-specific-entries) for the fix.
docs/examples/kubo-as-a-library/go.mod
+1 -1
@@ -7,7 +7,7 @@ go 1.26.2
7 replace github.com/ipfs/kubo => ./../../..
8
9 require (
10 - github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6
10 + github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e
11 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
12 github.com/libp2p/go-libp2p v0.48.0
13 github.com/multiformats/go-multiaddr v0.16.1
docs/examples/kubo-as-a-library/go.sum
+2 -2
@@ -352,8 +352,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
352 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
353 github.com/ipfs/bbloom v0.1.0 h1:nIWwfIE3AaG7RCDQIsrUonGCOTp7qSXzxH7ab/ss964=
354 github.com/ipfs/bbloom v0.1.0/go.mod h1:lDy3A3i6ndgEW2z1CaRFvDi5/ZTzgM1IxA/pkL7Wgts=
355 -github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6 h1:nTSsEEQv4O89Z0/iCSo5Zu+cB7qtmTg6OzquMKDhay0=
356 -github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6/go.mod h1:o+77q6sNLx04X1pWLTICgi+MimNAKFy9HJ2qfhNUTRs=
355 +github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e h1:kuArrVMzJ0eBOu4NsG7V4hPHLMn7o8UUHOOTA8+hPZI=
356 +github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e/go.mod h1:o+77q6sNLx04X1pWLTICgi+MimNAKFy9HJ2qfhNUTRs=
357 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
358 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
359 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
go.mod
+1 -1
@@ -21,7 +21,7 @@ require (
21 github.com/hashicorp/go-version v1.9.0
22 github.com/ipfs-shipyard/nopfs v0.0.14
23 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0
24 - github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6
24 + github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e
25 github.com/ipfs/go-block-format v0.2.3
26 github.com/ipfs/go-cid v0.6.1
27 github.com/ipfs/go-cidutil v0.1.1
go.sum
+2 -2
@@ -392,8 +392,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
392 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
393 github.com/ipfs/bbloom v0.1.0 h1:nIWwfIE3AaG7RCDQIsrUonGCOTp7qSXzxH7ab/ss964=
394 github.com/ipfs/bbloom v0.1.0/go.mod h1:lDy3A3i6ndgEW2z1CaRFvDi5/ZTzgM1IxA/pkL7Wgts=
395 -github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6 h1:nTSsEEQv4O89Z0/iCSo5Zu+cB7qtmTg6OzquMKDhay0=
396 -github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6/go.mod h1:o+77q6sNLx04X1pWLTICgi+MimNAKFy9HJ2qfhNUTRs=
395 +github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e h1:kuArrVMzJ0eBOu4NsG7V4hPHLMn7o8UUHOOTA8+hPZI=
396 +github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e/go.mod h1:o+77q6sNLx04X1pWLTICgi+MimNAKFy9HJ2qfhNUTRs=
397 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
398 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
399 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
test/dependencies/go.mod
+1 -1
@@ -135,7 +135,7 @@ require (
135 github.com/huin/goupnp v1.3.0 // indirect
136 github.com/inconshreveable/mousetrap v1.1.0 // indirect
137 github.com/ipfs/bbloom v0.1.0 // indirect
138 - github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6 // indirect
138 + github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e // indirect
139 github.com/ipfs/go-bitfield v1.1.0 // indirect
140 github.com/ipfs/go-block-format v0.2.3 // indirect
141 github.com/ipfs/go-cid v0.6.1 // indirect
test/dependencies/go.sum
+2 -2
@@ -452,8 +452,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
452 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
453 github.com/ipfs/bbloom v0.1.0 h1:nIWwfIE3AaG7RCDQIsrUonGCOTp7qSXzxH7ab/ss964=
454 github.com/ipfs/bbloom v0.1.0/go.mod h1:lDy3A3i6ndgEW2z1CaRFvDi5/ZTzgM1IxA/pkL7Wgts=
455 -github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6 h1:nTSsEEQv4O89Z0/iCSo5Zu+cB7qtmTg6OzquMKDhay0=
456 -github.com/ipfs/boxo v0.39.1-0.20260504132022-a1b91c48cae6/go.mod h1:o+77q6sNLx04X1pWLTICgi+MimNAKFy9HJ2qfhNUTRs=
455 +github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e h1:kuArrVMzJ0eBOu4NsG7V4hPHLMn7o8UUHOOTA8+hPZI=
456 +github.com/ipfs/boxo v0.39.1-0.20260514201954-b2b5d8a2ae5e/go.mod h1:o+77q6sNLx04X1pWLTICgi+MimNAKFy9HJ2qfhNUTRs=
457 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
458 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
459 github.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk=