Repository navigation
Decentralized controller consistency - #1273
leonard-amsler wants to merge 7 commits into
Conversation
…zed-controller-consistency
JulienVig
left a comment
There was a problem hiding this comment.
All good! Only minor comments. Fyi, I will follow up this PR with another one for these points:
- create an abort signal when the participant disconnects manually to stop any promise it was waiting on
- disconnect server-side any peer that timeouts on PeerIsReady
- check that ConnectionsReady only come from peers that sent PeerIsReady first (an attacker could send a ConnectionsReady during training and currently it would increment the round)
| this.#connectionRetry = 0; | ||
| // Restart the timeout after sending retry messages | ||
| this.startTimeout(); | ||
|
|
There was a problem hiding this comment.
Let's make sure we add a timeout back here. If we are sending a RetryPeerConnections it means one peer failed to connect in time so it is likely that it will fail again. We need a timeout to ensure the server doesn't get stuck waiting and can exclude the peer.
| const providerInfo = await waitMessageWithTimeout( | ||
| this.server, | ||
| MType.ModelProviderInfo, | ||
| this.task.trainingInformation.maxModelSyncTime, | ||
| "Timeout while waiting for the latest model provider", | ||
| ); |
There was a problem hiding this comment.
I think we should also check for an abort signal here. There is still the timeout as fallback but it would be cleaner to fail with the proper cause I think
| if (this.#timeout !== undefined) { | ||
| clearTimeout(this.#timeout); | ||
| this.#timeout = undefined; | ||
| } |
There was a problem hiding this comment.
you can use this.#clearTimeout() now
| * Complete list of client ids that have connected their websocket | ||
| * Make sure two clients don't share the same ID. | ||
| */ | ||
| protected clientIds = new Set<NodeID>(); |
There was a problem hiding this comment.
Can you import Set from immutable rather than using the native JS Set? To be consistent with Map
| protected clientIds = new Set<NodeID>(); | ||
| /** | ||
| * Number of ClientConnected messages each client's socket sent. | ||
| * We answer them with the global weights, so a client resending it |
There was a problem hiding this comment.
| * We answer them with the global weights, so a client resending it | |
| * In FL we answer with the global weights, so a client resending it |
| * - `connections` (inherited): map between the ids of clients | ||
| * that completed the connection handshake and their socket. | ||
| * - `#roundPeers`: the nodes that want to join the current round and their readiness status. | ||
| * - `#connectFinishedNodes`: the nodes that have completed the connection handshake and are ready for the current round. |
There was a problem hiding this comment.
| * - `#connectFinishedNodes`: the nodes that have completed the connection handshake and are ready for the current round. | |
| * - `#connectFinishedNodes`: the nodes that have completed their peer-to-peer webRTC connections and are ready for the current round. |
To make sure it's not confused with the connection handshake with the server
| ); | ||
| } | ||
|
|
||
| protected override connectClient(nodeId: string, ws: WebSocket): void { |
There was a problem hiding this comment.
| protected override connectClient(nodeId: string, ws: WebSocket): void { | |
| protected override connectClient(nodeId: NodeID, ws: WebSocket): void { |
| } | ||
| } | ||
|
|
||
| protected override disconnectClient(nodeId: string): void { |
There was a problem hiding this comment.
| protected override disconnectClient(nodeId: string): void { | |
| protected override disconnectClient(nodeId: NodeID): void { |
Context
#1227 reworked the federated setting. This PR moves the shared parts to the abstract classes and uses them also in the decentralized setting.
Server
send,crashClient,disconnect, the client ids, theClientConnectedcounter and the connect/disconnect cleanup from the federated controller toTrainingController, so both controllers share them.ClientConnectedClientConnectedClientConnectedgets the same answer again, without counting the peer twice or notifying the other peers.sendhelper, so a failed send disconnects the peer.#syncingNodes.#methods.RetryPeerConnections, and thenConnectionFail, to peers that were fine. There is now one timer perPeersForRound, and the retry count restarts at each round.Client
disconnect()is now shared inClient. It closes the server connection if there is one (local training) and stops waiting for participants, so a client no longer keeps waiting after disconnecting. It also works when called multiple times.sendAndWaitWithRetry.ClientCrashErrorwhen the server crashes it, at the start of a round and while waiting for the server.CrashClientis now part of the decentralized messages.Tests
Fixes #1250