sdk/python: renew the relay reservation before the router drops it - #502
Merged
Merged
Conversation
go-libp2p's relay grants a reservation for one hour (ReservationTTL) and garbage-collects it on expiry. The Python SDK reserved once in join and never again, so after an hour every dial to the member through the router failed with NO_RESERVATION while it kept advertising the relayed address. On bananas the python canary became unreachable exactly one hour after each rollout and both probe CronJobs failed until the next one restarted it; the JS SDK was unaffected, js-libp2p's listener renews on its own. Add a reservation loop to the session that reserves again two minutes before the expiry the router returned, the lead go-libp2p's own clients use. The router forgets an admission when the connection closes, so a renewal that finds the router disconnected dials and authenticates again first. A failed renewal is retried; the relay keeps the old reservation until it expires. The fake router in the tests records handshakes and RESERVEs and grants a short TTL; the new test sees a renewal on the same admission, then drops the member and sees the next renewal run the handshake first.
Contributor
There was a problem hiding this comment.
Code Review
This pull request implements automatic relay reservation renewal and re-authentication for the Python SDK. It introduces a background reservation loop in MeshSession that monitors reservation expirations and triggers renewal before they lapse, re-dialing and re-authenticating if a router has disconnected. An integration test is added to verify this behavior. Feedback is provided to handle failures during the renewal process by disconnecting from the router, preventing a potential stuck state where subsequent retries skip dialing and authentication.
A renewal that failed after the dial, or a RESERVE refused on a connection the router no longer counts as admitted, left the connection open, and the next attempt saw the router as connected, skipped the handshake and sent the same RESERVE again. Disconnect on any failure so the retry dials and authenticates from scratch. Test: the fake relay refuses the second RESERVE; the third arrives after a second handshake.
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.
Both probe CronJobs on bananas failed from 19:30 UTC today (Testnet Health run 36052804226). Every failed probe died dialing the python canary through the router with
NO_RESERVATION (204).go-libp2p's relay grants a reservation for one hour (
ReservationTTL) and garbage-collects it on expiry. The Python SDK reserved once injoinand never again, so one hour after each rollout the python canary became unreachable through the router while still advertising the relayed address, until the next rollout restarted it. The JS SDK is unaffected: js-libp2p's circuit listener renews on its own. It did not show up before because the SDK canaries landed today and bananas was redeployed twice within the hour.MeshSession._reservation_loopreserves again two minutes before the expiry the router returned, the lead go-libp2p's own autorelay uses. A router that closed the connection forgets the admission, so a renewal that finds the router disconnected dials and authenticates again first. A failed renewal is retried; the relay keeps the old reservation until it expires.join(reservation_lead=...)exposes the lead; the retry reusesrefresh_retry.RelayDiscoveryre-reserves only after expiry, when the slot is already gone.Not related to #498: the relay limit is read when a circuit opens; the reservation TTL path is untouched, and the Go canaries kept passing.