Skip to content

Commit cb4a6db

Browse files
authored
perform partial room unloads when monolith is shutting down (#1183)
1 parent 82d5b6f commit cb4a6db

File tree

3 files changed

+43
-15
lines changed

3 files changed

+43
-15
lines changed

deploy/fly.prod.monolith.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
app = "ott-prod"
22
primary_region = "ewr"
3+
kill_timeout = 15
34

45
[build]
56
dockerfile = "monolith.Dockerfile"

deploy/fly.staging.monolith.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
app = "ott-staging"
22
primary_region = "ewr"
3+
kill_timeout = 15
34

45
[build]
56
dockerfile = "monolith.Dockerfile"

server/roommanager.ts

+41-15
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,23 @@ async function addRoom(room: Room) {
4343
bus.emit("load", room.name);
4444
}
4545

46+
let updaterInterval: NodeJS.Timer | null = null;
4647
export async function start() {
4748
log.info("Starting room manager");
4849

49-
setInterval(update, 1000);
50+
updaterInterval = setInterval(update, 1000);
51+
process.on("SIGINT", shutdown);
52+
process.on("SIGTERM", shutdown);
53+
}
54+
55+
async function shutdown() {
56+
log.info("Shutting down room manager");
57+
if (updaterInterval) {
58+
clearInterval(updaterInterval);
59+
updaterInterval = null;
60+
}
61+
await Promise.all(rooms.map(room => unloadRoom(room.name, { preserveRedis: true })));
62+
process.exit(0);
5063
}
5164

5265
export function redisStateToState(state: RoomStateFromRedis): RoomState {
@@ -151,23 +164,36 @@ export async function getRoom(
151164
return ok(room);
152165
}
153166

154-
export async function unloadRoom(roomName: string): Promise<void> {
167+
export async function unloadRoom(
168+
room: string | Room,
169+
options: Partial<{ preserveRedis: boolean }> = {}
170+
): Promise<void> {
171+
const opts = _.defaults(options, {
172+
preserveRedis: false,
173+
});
174+
155175
let idx = -1;
156-
for (let i = 0; i < rooms.length; i++) {
157-
if (rooms[i].name.toLowerCase() === roomName.toLowerCase()) {
158-
idx = i;
159-
break;
176+
if (typeof room === "string") {
177+
for (let i = 0; i < rooms.length; i++) {
178+
if (rooms[i].name.toLowerCase() === room.toLowerCase()) {
179+
idx = i;
180+
break;
181+
}
160182
}
183+
if (idx < 0) {
184+
throw new RoomNotFoundException(room);
185+
}
186+
room = rooms[idx];
161187
}
162-
if (idx >= 0) {
163-
log.info(`Unloading room: ${roomName}`);
164-
await rooms[idx].onBeforeUnload();
165-
} else {
166-
throw new RoomNotFoundException(roomName);
167-
}
188+
const roomName = room.name;
189+
log.info(`Unloading room: ${roomName}`);
190+
await room.onBeforeUnload();
191+
idx = rooms[idx].name === room.name ? idx : rooms.indexOf(room); // because the index may have changed across await boundaries
168192
rooms.splice(idx, 1);
169-
await redisClient.del(`room:${roomName}`);
170-
await redisClient.del(`room-sync:${roomName}`);
193+
if (!opts.preserveRedis) {
194+
await redisClient.del(`room:${roomName}`);
195+
await redisClient.del(`room-sync:${roomName}`);
196+
}
171197
bus.emit("unload", roomName);
172198
}
173199

@@ -184,7 +210,7 @@ export function clearRooms(): void {
184210
/** Unload all rooms off of this node. Intended to only be used in tests. */
185211
export async function unloadAllRooms(): Promise<void> {
186212
const names = rooms.map(r => r.name);
187-
await Promise.all(names.map(unloadRoom));
213+
await Promise.all(names.map(name => unloadRoom(name)));
188214
}
189215

190216
export function publish(roomName: string, msg: ServerMessage) {

0 commit comments

Comments
 (0)