-
Notifications
You must be signed in to change notification settings - Fork 0
Add a cleanup mechanism for old db entries #104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add a cleanup mechanism for old db entries #104
Conversation
…he channel is closed Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
flottform/server/src/database.ts
Outdated
| this.cleanupIntervalId = setInterval(() => { | ||
| // Loop over all entries and delete the stale ones. | ||
| const now = Date.now(); | ||
| for (const [endpointId, endpointInfo] of this.map) { | ||
| const lastUpdated = endpointInfo.lastUpdate; | ||
| if (now - lastUpdated > this.entryTTL) { | ||
| this.map.delete(endpointId); | ||
| console.log(`Cleaned up stale entry: ${endpointId}`); | ||
| } | ||
| } | ||
| }, this.cleanupPeriod); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| this.cleanupIntervalId = setInterval(() => { | |
| // Loop over all entries and delete the stale ones. | |
| const now = Date.now(); | |
| for (const [endpointId, endpointInfo] of this.map) { | |
| const lastUpdated = endpointInfo.lastUpdate; | |
| if (now - lastUpdated > this.entryTTL) { | |
| this.map.delete(endpointId); | |
| console.log(`Cleaned up stale entry: ${endpointId}`); | |
| } | |
| } | |
| }, this.cleanupPeriod); | |
| const cleanupFn = () => { | |
| const nextStartTime = Date.now() + this.cleanupPeriod; | |
| // Loop over all entries and delete the stale ones. | |
| const now = Date.now(); | |
| for (const [endpointId, endpointInfo] of this.map) { | |
| const lastUpdated = endpointInfo.lastUpdate; | |
| if (now - lastUpdated > this.entryTTL) { | |
| this.map.delete(endpointId); | |
| console.log(`Cleaned up stale entry: ${endpointId}`); | |
| } | |
| } | |
| this.cleanupIntervalId = setTimeout(cleanupFn, Math.max(0, Date.now - nextStartTime)); | |
| }; | |
| this.cleanupIntervalId = setTimeout(cleanupFn, this.cleanupPeriod); |
flottform/server/src/database.ts
Outdated
| private stopCleanup() { | ||
| // Clear the interval to stop cleanup | ||
| if (this.cleanupIntervalId) { | ||
| clearInterval(this.cleanupIntervalId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| clearInterval(this.cleanupIntervalId); | |
| clearTimeout(this.cleanupIntervalId); |
Narigo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, please add tests for the cleanup
…-entries Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
…formDatabase to allow testing Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Narigo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pushing this! I had a look into it and left a few comments - wondering whether it would be easy to use fake timers to not having to wait for over a second in the unit tests
| ).rejects.toThrow( | ||
| /clientKey is wrong: Another peer is already connected and you cannot change this info without the correct key anymore. If you lost your key, initiate a new Flottform connection./i | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since peerkey isn't used in this error message but I don't see a change to the error itself, was/is this test not working? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that test was not working since as you've said the string 'peerkey' is not used anymore and is replaced by this string: 'clientKey is wrong: Another peer is already connected and you cannot change this info without the correct key anymore. If you lost your key, initiate a new Flottform connection.'
--> I fixed it in this commit: 481b54b
| }); | ||
|
|
||
| describe('startCleanup()', () => { | ||
| function sleep(ms: number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make totally clear this expects you to wait for it, I would add this:
| function sleep(ms: number) { | |
| async function sleep(ms: number): Promise<void> { |
But the helper function itself could also go somewhere else and doesn't need to be inside the describe block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I changed to fake timers like you suggested, I don't think we need it anymore!
flottform/server/src/database.ts
Outdated
| private map = new Map<EndpointId, EndpointInfo>(); | ||
| private cleanupTimeoutId: NodeJS.Timeout | null = null; | ||
| private cleanupPeriod: number; | ||
| private entryTTL: number; // Time-to-Live for each entry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about entryTimeoutInMs to make it clear we're expecting milliseconds here? Also, TTL gets explained in a comma, so I'd suggest to get rid of it by not using an abbreviation. Abbreviations in general, I'd favor entryTtl, so if we end up having another abbreviation before or after this one, it can stay consistent (HttpId vs HTTPID or something along those lines...)
flottform/server/src/database.ts
Outdated
| } | ||
|
|
||
| private cleanupFn() { | ||
| if (!this.map || this.map.size === 0) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we fall down to size 0, it will never call the cleanupFn again. Is there a test for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cleanup mechanism is designed to run periodically, regardless of whether the map is empty at the time of execution. The purpose is to ensure stale entries are regularly deleted, even if none exist during a specific cleanup cycle. This mechanism continues to run until the server hosting the database is stopped.
For example, while the map might be empty during the first cleanup call, it’s possible that by the next cycle, new entries have been added, with some of them becoming stale. Stopping the cleanup when the map is empty will lead to not cleaning up stale entries in subsequent cycles. Therefore, it’s crucial that the cleanup function runs unconditionally.
flottform/server/src/database.ts
Outdated
| cleanupPeriod = 30 * 60 * 1000, | ||
| entryTTL = 25 * 60 * 1000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default values are here a second time. Can we move them into a constant at the beginning of the file? const DEFAULT_CLEANUP_PERIOD = 30 * 60 * 1000; and const DEFAULT_ENTRY_TIMEOUT_IN_MS = 25 * 60 * 1000, then use
| cleanupPeriod = 30 * 60 * 1000, | |
| entryTTL = 25 * 60 * 1000 | |
| cleanupPeriod = DEFAULT_CLEANUP_PERIOD, | |
| entryTTL = DEFAULT_ENTRY_TIMEOUT_IN_MS |
| // Sleep for enough time to trigger the first cleanup | ||
| await sleep(1100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to use fake timers for this and not actually wait for a second?
…timers Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Narigo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need some way of heartbeat from the frontend to keep the connection open or react to a closed channel by the server. This needs changes to the frontend as well
|
|
||
| try { | ||
| this.rtcConfiguration.iceServers = await this.fetchIceServers(baseApi); | ||
| this.rtcConfiguration.iceServers = await this.fetchIceServers(this.baseApi); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing this.baseApi shouldn't be necessary if we use this.baseApi in the function instead of a parameter
flottform/server/src/database.ts
Outdated
| session, | ||
| iceCandidates | ||
| iceCandidates, | ||
| lastUpdate = Date.now() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be done in the function directly where it's necessary instead of passing an argument (and potentially overwriting it)
| entry.lastUpdate = Date.now(); | ||
| const { hostKey: _ignore1, clientKey: _ignore2, ...endpoint } = entry; | ||
|
|
||
| return endpoint; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lastUpdate should not be exposed to the client as it should only be used internally for cleanup
| lastUpdate: Date.now() | ||
| }; | ||
| this.map.set(entry.endpointId, entry); | ||
| return entry; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exposing lastUpdate, see comment below
| clientKey, | ||
| session: answer, | ||
| iceCandidates: [], | ||
| lastUpdate: Date.now() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lastUpdate should be taken care of internally only - no need to set it here
| clientKey, | ||
| session: answer, | ||
| iceCandidates: [], | ||
| lastUpdate: Date.now() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lastUpdate should be taken care of internally only - no need to set it here
|
As discussed, this should also include some kind of heartbeat from the host - basically updating the info every 5 minutes to what it was before, just to keep the lastUpdate until the host disconnects and then this endpoint will be removed after 30 minutes |
Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Signed-off-by: nidhal-labidi <nidhal.labidi@compose.us>
Checklist
Reviewer
Changes
close(in the classes:FlottformFileInputHostandFlottformTextInputHost) whenever the file/text transfer is done so that theclosemethod inFlottformChannelHosttriggers aDELETE requestto remove the entry from the signaling server DB.