Commit 9577473
fix(node): make endpoint.state[id] and ClientNode.toString teardown-safe (#3680)
* fix(node): cache resolved peer address to make ClientNode toString teardown-safe
ClientNode.toString() — invoked from Behaviors and Endpoint error message
construction — could throw [destroyed-dependency] during ServerNode shutdown:
the storage fallback in peerAddress went through ServerNodeStore.clientStores,
which asserts active construction and is already in Closing state by the time
the WAL final snapshot runs. The throw then masked whatever original error
triggered toString().
peerAddress now mirrors the commissioning behavior state into a cache field
whenever the backing is loaded (set OR cleared, so a decommission does not
leave a stale value), falls back to the cache when the backing is gone, and
accepts DependencyLifecycleError around the storage probe so teardown reads
return undefined rather than throwing. eraseWithMutex clears the cache so
re-commissioning can publish a new address.
Adds a regression test that closes the controller and verifies peerAddress
and toString continue to resolve.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(node): make endpoint.state[behaviorId] return undefined during teardown
Behaviors.close() destroys backings but leaves the augmented endpoint.state[id]
property descriptors in place because reuse paths (factory reset) re-activate
through the same getter without re-running the constructor. Post-close access
therefore re-entered #backingFor on a missing backing and threw
BehaviorInitializationError; constructing that error involved ${this.#endpoint}
which cascaded through toString → identity → peerAddress → storage and
surfaced as a misleading "Snapshot failed" warning during ServerNode shutdown.
The getter now checks the endpoint construction status: in Destroying or
Destroyed it returns undefined, leaving Active/Initializing paths (including
late activation) unchanged.
Adds a regression test verifying state access on a closed peer returns
undefined rather than throwing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(node): clear cached peer address on soft reset too
Copilot review on #3680 noted that ClientNode.reset() (soft reset, without
storage erase) closes behaviors but leaves #cachedPeerAddress in place. If
the node is then re-commissioned to a different fabric, peerAddress would
return the stale cached value until the new commissioning state loads.
Add a resetWithMutex override that clears the cache. The explicit clear in
eraseWithMutex stays because that path uses super.resetWithMutex() (static
dispatch), which skips this override.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>1 parent 05db23e commit 9577473
3 files changed
Lines changed: 81 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
821 | 821 | | |
822 | 822 | | |
823 | 823 | | |
824 | | - | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
825 | 835 | | |
826 | 836 | | |
827 | 837 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
| |||
47 | 48 | | |
48 | 49 | | |
49 | 50 | | |
| 51 | + | |
50 | 52 | | |
51 | 53 | | |
52 | 54 | | |
| |||
206 | 208 | | |
207 | 209 | | |
208 | 210 | | |
209 | | - | |
210 | 211 | | |
211 | | - | |
212 | | - | |
213 | 212 | | |
214 | | - | |
215 | | - | |
| 213 | + | |
216 | 214 | | |
217 | 215 | | |
218 | 216 | | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
219 | 222 | | |
220 | 223 | | |
221 | 224 | | |
| |||
274 | 277 | | |
275 | 278 | | |
276 | 279 | | |
277 | | - | |
278 | | - | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
279 | 292 | | |
280 | | - | |
281 | | - | |
282 | | - | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
283 | 303 | | |
284 | 304 | | |
285 | | - | |
| 305 | + | |
286 | 306 | | |
287 | 307 | | |
288 | 308 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1362 | 1362 | | |
1363 | 1363 | | |
1364 | 1364 | | |
| 1365 | + | |
| 1366 | + | |
| 1367 | + | |
| 1368 | + | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
| 1378 | + | |
| 1379 | + | |
| 1380 | + | |
| 1381 | + | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
| 1386 | + | |
| 1387 | + | |
| 1388 | + | |
| 1389 | + | |
| 1390 | + | |
| 1391 | + | |
| 1392 | + | |
| 1393 | + | |
| 1394 | + | |
| 1395 | + | |
| 1396 | + | |
| 1397 | + | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
| 1401 | + | |
| 1402 | + | |
| 1403 | + | |
1365 | 1404 | | |
1366 | 1405 | | |
1367 | 1406 | | |
| |||
0 commit comments