directory_server.heartbeat
directory_server.heartbeat
Heartbeat liveness detection for directory server peers.
Implements the PING/PONG heartbeat protocol compatible with joinmarket-rs. The directory server periodically probes idle peers and evicts unresponsive ones.
Protocol flow (matching joinmarket-rs behavior):
1. Every sweep_interval_sec seconds, run a heartbeat sweep.
2. Hard-evict all peers whose last_seen exceeds hard_evict_sec.
3. Probe peers idle longer than idle_threshold_sec:
- Ping-capable peers: send PING (type 798), mark pong_pending.
- Non-ping makers: send unicast !orderbook to elicit an offer
re-announcement (which updates last_seen).
- Non-ping takers/watchers: no probe -- they will be hard-evicted
when hard_evict_sec is reached.
4. Wait pong_wait_sec seconds for responses.
5. Evict all peers still having pong_pending = True.
Timing constants match joinmarket-rs defaults: - sweep_interval_sec = 60 - idle_threshold_sec = 600 (10 minutes) - hard_evict_sec = 1500 (25 minutes) - pong_wait_sec = 30
Attributes
EvictCallback = Callable[[str, str], Awaitable[None]]
module-attribute
SendCallback = Callable[[str, bytes], Awaitable[None]]
module-attribute
Classes
HeartbeatConfig
dataclass
Heartbeat timing configuration.
Defaults match joinmarket-rs for interoperability.
Source code in directory_server/src/directory_server/heartbeat.py
44 45 46 47 48 49 50 51 52 53 54 | |
Attributes
hard_evict_sec: float = 1500.0
class-attribute
instance-attribute
idle_threshold_sec: float = 600.0
class-attribute
instance-attribute
pong_wait_sec: float = 30.0
class-attribute
instance-attribute
sweep_interval_sec: float = 60.0
class-attribute
instance-attribute
HeartbeatManager
Manages periodic heartbeat sweeps for the directory server.
Args:
peer_registry: Registry to query peer state and last_seen.
send_callback: Async callable (peer_key, data_bytes) -> None.
evict_callback: Async callable (peer_key, reason) -> None
that disconnects and unregisters a peer.
config: Timing configuration.
Source code in directory_server/src/directory_server/heartbeat.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | |
Attributes
config = config or HeartbeatConfig()
instance-attribute
evict_callback = evict_callback
instance-attribute
peer_registry = peer_registry
instance-attribute
pong_pending: frozenset[str]
property
Read-only view of peers with pending pongs (for testing).
send_callback = send_callback
instance-attribute
server_nick = server_nick
instance-attribute
Functions
__init__(peer_registry: PeerRegistry, send_callback: SendCallback, evict_callback: EvictCallback, config: HeartbeatConfig | None = None, server_nick: str = '') -> None
Source code in directory_server/src/directory_server/heartbeat.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | |
handle_pong(peer_key: str) -> None
Called by the message router when a PONG is received.
Clears pong_pending so the peer is not evicted.
Source code in directory_server/src/directory_server/heartbeat.py
111 112 113 114 115 116 117 118 | |
start() -> None
Start the background heartbeat loop.
Source code in directory_server/src/directory_server/heartbeat.py
88 89 90 91 92 93 94 95 96 97 98 | |
stop() -> None
async
Stop the background heartbeat loop.
Source code in directory_server/src/directory_server/heartbeat.py
100 101 102 103 104 105 106 107 108 109 | |