Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 3.8k
fix(realtime): address post-merge review-comment findings#5937
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
816d0ec954ae21895a792a76e12effbf408File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -149,6 +149,10 @@ export class MemoryRoomManager implements IRoomManager { | ||
| return this.rooms.has(roomKey(room)) | ||
| } | ||
| async deleteRoom(room: RoomRef): Promise<void> { | ||
| this.rooms.delete(roomKey(room)) | ||
| } | ||
cursor[bot] marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| async updateUserActivity( | ||
| room: RoomRef, | ||
| socketId: string, | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -311,6 +311,17 @@ export class RedisRoomManager implements IRoomManager { | ||
| return exists > 0 | ||
| } | ||
| async deleteRoom(room: RoomRef): Promise<void> { | ||
| // Log AND rethrow (like addUserToRoom): a failed wipe must not be reported as a | ||
| // clean deletion by the caller — the request surfaces it (and can be retried). | ||
| try { | ||
| await this.redis.del([KEYS.roomUsers(room), KEYS.roomMeta(room)]) | ||
greptile-apps[bot] marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } catch (error) { | ||
| logger.error(`Failed to delete room ${room.type}:${room.id}:`, error) | ||
| throw error | ||
| } | ||
| } | ||
waleedlatif1 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| async updateUserActivity( | ||
| room: RoomRef, | ||
| socketId: string, | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -22,29 +22,44 @@ export class WorkflowRoomService { | ||
| logger.info(`Handling workflow deletion notification for ${workflowId}`) | ||
| const room = workflowRoom(workflowId) | ||
| const users = await this.manager.getRoomUsers(room) | ||
| if (users.length === 0) { | ||
| logger.debug(`No active users found for deleted workflow ${workflowId}`) | ||
| return | ||
| } | ||
| const name = roomName(room) | ||
| // Always notify — reach every socket still in the Socket.IO room so the client | ||
| // clears the deleted workflow, even if that socket's Redis presence was evicted | ||
| // (in which case it would be missing from getRoomUsers). Emitting to an empty | ||
| // room is a harmless no-op. | ||
| this.manager.emitToRoom(room, 'workflow-deleted', { | ||
| workflowId, | ||
| message: 'This workflow has been deleted', | ||
| timestamp: Date.now(), | ||
| }) | ||
waleedlatif1 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| // Clean per-socket state for every socket that is either a live Socket.IO member | ||
| // OR still has presence — so an evicted/late-joined socket's room mapping and | ||
| // session are dropped too, not just the presence-tracked ones. | ||
| const socketIds = new Set<string>() | ||
| try { | ||
| const liveSockets = await this.manager.io.in(name).fetchSockets() | ||
| for (const s of liveSockets) socketIds.add(s.id) | ||
| } catch (error) { | ||
| logger.warn(`Could not enumerate sockets for deleted workflow ${workflowId}`, error) | ||
waleedlatif1 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| for (const user of await this.manager.getRoomUsers(room)) socketIds.add(user.socketId) | ||
greptile-apps[bot] marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| // Remove every socket from the Socket.IO room (cross-pod via the Redis adapter). | ||
| const name = roomName(room) | ||
| await this.manager.io.in(name).socketsLeave(name) | ||
| // Drop presence state for each socket; empty-room cleanup is handled by the manager. | ||
| for (const user of users) { | ||
| await this.manager.removeUserFromRoom(room, user.socketId) | ||
| for (const socketId of socketIds) { | ||
| await this.manager.removeUserFromRoom(room, socketId) | ||
waleedlatif1 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
waleedlatif1 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. waleedlatif1 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| // Final unconditional wipe — the workflow is gone, so no room state may linger | ||
| // even if a per-socket removal failed (matches the pre-refactor managers, which | ||
| // ended deletion with an unconditional room drop). | ||
| await this.manager.deleteRoom(room) | ||
| logger.info( | ||
| `Cleaned up workflow room ${workflowId} after deletion (${users.length} users disconnected)` | ||
| `Cleaned up workflow room ${workflowId} after deletion (${socketIds.size} sockets removed)` | ||
| ) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.