@mulingai-npm/redis 3.35.6 → 3.35.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,12 +19,19 @@ export declare class DemoRoomPoolManager {
19
19
  * Called once at service startup. Idempotent — safe to call on restart.
20
20
  */
21
21
  initPool(roomIds: number[]): Promise<void>;
22
+ /**
23
+ * Scan all rooms and reclaim any with expired sessions.
24
+ * Rooms whose session has expired (or session key is missing) are returned to the available pool.
25
+ * Returns number of rooms reclaimed.
26
+ */
27
+ reclaimExpiredRooms(): Promise<number>;
22
28
  /**
23
29
  * Assign an available room to a demo user.
24
30
  * Returns null if no rooms available.
25
31
  * Atomic: SPOP removes from available set in one operation.
32
+ * If no rooms available, attempts to reclaim rooms with expired sessions first.
26
33
  */
27
- assignRoom(emailHash: string, demoSessionId: string, durationMs: number): Promise<{
34
+ assignRoom(emailHash: string, demoSessionId: string, durationMs: number, email?: string): Promise<{
28
35
  roomId: number;
29
36
  expiresAt: number;
30
37
  } | null>;
@@ -40,22 +40,55 @@ class DemoRoomPoolManager {
40
40
  }
41
41
  }
42
42
  }
43
+ /**
44
+ * Scan all rooms and reclaim any with expired sessions.
45
+ * Rooms whose session has expired (or session key is missing) are returned to the available pool.
46
+ * Returns number of rooms reclaimed.
47
+ */
48
+ async reclaimExpiredRooms() {
49
+ const allRoomIds = await this.redisClient.smembers('demo:pool:all');
50
+ const availableRoomIds = await this.redisClient.smembers('demo:pool:available');
51
+ const availableSet = new Set(availableRoomIds);
52
+ let reclaimed = 0;
53
+ for (const rid of allRoomIds) {
54
+ if (availableSet.has(rid))
55
+ continue; // Already available
56
+ const expiresAtStr = await this.redisClient.hget(`demo:pool:room:${rid}:session`, 'expiresAt');
57
+ if (!expiresAtStr || Date.now() >= parseInt(expiresAtStr)) {
58
+ // Session expired or key missing — reclaim
59
+ await this.redisClient.del(`demo:pool:room:${rid}:session`);
60
+ await this.redisClient.del(`demo:pool:room:${rid}:credits`);
61
+ await this.redisClient.sadd('demo:pool:available', rid);
62
+ reclaimed++;
63
+ }
64
+ }
65
+ return reclaimed;
66
+ }
43
67
  /**
44
68
  * Assign an available room to a demo user.
45
69
  * Returns null if no rooms available.
46
70
  * Atomic: SPOP removes from available set in one operation.
71
+ * If no rooms available, attempts to reclaim rooms with expired sessions first.
47
72
  */
48
- async assignRoom(emailHash, demoSessionId, durationMs) {
73
+ async assignRoom(emailHash, demoSessionId, durationMs, email) {
49
74
  // Atomic pop from available set
50
- const roomIdStr = await this.redisClient.spop('demo:pool:available');
75
+ let roomIdStr = await this.redisClient.spop('demo:pool:available');
76
+ // If no rooms available, try reclaiming expired sessions
77
+ if (!roomIdStr) {
78
+ const reclaimed = await this.reclaimExpiredRooms();
79
+ if (reclaimed > 0) {
80
+ roomIdStr = await this.redisClient.spop('demo:pool:available');
81
+ }
82
+ }
51
83
  if (!roomIdStr)
52
- return null; // All rooms busy
84
+ return null; // Truly all rooms busy
53
85
  const roomId = parseInt(roomIdStr);
54
86
  const now = Date.now();
55
87
  const expiresAt = now + durationMs;
56
88
  // Store session info
57
89
  await this.redisClient.hset(`demo:pool:room:${roomId}:session`, {
58
90
  emailHash,
91
+ email: email || '',
59
92
  demoSessionId,
60
93
  startedAt: now.toString(),
61
94
  expiresAt: expiresAt.toString(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mulingai-npm/redis",
3
- "version": "3.35.6",
3
+ "version": "3.35.8",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {