Repository navigation
Unit tests federated controller + fixes - #1227
leonard-amsler wants to merge 24 commits into
Conversation
|
Regarding known issue not fixed #1: how would you skip the ClientConnected message? In FL for example, it's currently used to let the server know how many contributions it should wait for and send the clients the base model |
…t a connection message
e51de03 to
979da3f
Compare
|
New progress on the PR:
|
…-federated-controller
JulienVig
left a comment
There was a problem hiding this comment.
Thanks for the great work! I left mostly superficial comments and a bit of refactoring but there are two points I would like to discuss:
- What should the server answer to a client that sent a future contribution?
- Sending the model weights every time we receive a Client Connected sounds a bit risky regarding DDoS attacks, I think we should implement a counter
…ons from the federated specs
…stead of private functions
91e94d2 to
e4cc7e9
Compare
…oid waiting after reconnection
New state
Tests
Notes
|
Description of the mechanism to make a webapp test with a scripted serverCypress can intercept HTTP requests by calling In order to make a test that relies on websocket connections of the server (such as
How the scripted run works
The regular e2e tests are unchanged. They keep |
JulienVig
left a comment
There was a problem hiding this comment.
Thanks for the great work, only nitpicking comments about names and documentation. I will create a follow up PR to yours to address a couple things that I realized when reviewing this PR. I'll let you know exactly what it's adressing so that we don't fix the same things in your next branch
| messages.isMessageFromServer, // can only receive federated message types from the server | ||
| messages.isMessageToServer, // idem for messages that the client can send |
There was a problem hiding this comment.
| messages.isMessageFromServer, // can only receive federated message types from the server | |
| messages.isMessageToServer, // idem for messages that the client can send | |
| messages.isMessageFromServer, | |
| messages.isMessageToServer, |
The comments are outdated now
| readonly #preprocessOnce: boolean; | ||
| // Forwarded to compatible models to identify this client in debug output. | ||
| readonly #debugLabel?: string; | ||
| #closed: boolean; |
There was a problem hiding this comment.
Can you add a comment describing the attribute?
There was a problem hiding this comment.
Fyi, you can also declare it directly in the constructor arguments:
constructor(
...
#closed = false,
...
)| */ | ||
| async close(): Promise<void> { | ||
| if (this.#closed) return; | ||
| this.#closed = true; |
There was a problem hiding this comment.
We should set the flag only once the cleanup has been successful in case something interrupts it so I think it's better to move it done to the very bottom (after the finally, not inside)
| return; | ||
| } else if (e instanceof ClientCrashError) { | ||
| toaster.error( | ||
| "The server stopped your training.<br/>Please rejoin the training by refreshing the page.", |
There was a problem hiding this comment.
| "The server stopped your training.<br/>Please rejoin the training by refreshing the page.", | |
| "The server have disconnected you due to an unexpected event.<br/> Feel free to rejoin the training.", |
Let's not try to troubleshoot too much or be too precise in the error message. One future feature is to preserve the state when refreshing so this message would get outdated and we also don't know whether this hypothetical error would actually go away by rejoining.
| /** | ||
| * Maximum number of times a client can try to connect with the same client ID. | ||
| */ | ||
| static readonly MAX_CLIENT_CONNECTED_PER_SOCKET = 5; |
There was a problem hiding this comment.
| static readonly MAX_CLIENT_CONNECTED_PER_SOCKET = 5; | |
| static readonly MAX_CLIENT_CONNECTION_RETRY = 5; |
I know that it's the name of the message type but I find the variable name confusing on its own, it sounds like we could connect up to 5 clients per socket.
| import { goToTaskOverview } from "../../../support/training"; | ||
|
|
||
| describe("training page", () => { | ||
| it("tells the user when the server make the client crash stops the training", () => { |
There was a problem hiding this comment.
| it("tells the user when the server make the client crash stops the training", () => { | |
| it("tells the user when the server crashes the client", () => { |
| payload: | ||
| this.#aggregator.round === 0 | ||
| ? undefined | ||
| ? undefined // Optimization: no needs to send the initial weights, the client already has them |
There was a problem hiding this comment.
| ? undefined // Optimization: no needs to send the initial weights, the client already has them | |
| ? undefined // Optimization: no need to send the initial weights, the client already has them |
| // Kept last as the enum values are what goes over the wire. | ||
| ParticipantsUpdate, | ||
| CrashClient, |
There was a problem hiding this comment.
Can you document what the CrashClient message is?
This PR involves:
Unit tests:
implemented at: server/tests/unit/federated_controller.spec.ts
18 tests in three groups: join handshake (3), aggregation (8, one commented out - see know issue), leaving and reset (7)
Controller discovered bugs:
Aggregator bugs:
Known issue but not fixed:
Fixes #1220, fixes #1221, fixes #1222