mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-05-18 20:08:19 +00:00
feat(maint): session-status endpoint for agent picker
Unlock Agent / Force Ready shortcuts used to read the target agentId from localStorage helix_agent_config — supervisors don't have that set and got 400 'agentId required'.
- SessionService.listLockedSessions() — SCAN over agent:session:*
- POST /api/maint/session-status returns { locked, free } by joining
the platform Agent entities against Redis session locks
- orphan locks (Redis key with no matching Agent record) surface in
the Locked bucket so the operator can still clear stale lock state
This commit is contained in:
@@ -55,6 +55,26 @@ export class SessionService {
|
||||
await this.redis.del(this.key(agentId));
|
||||
}
|
||||
|
||||
// Enumerate every active session lock so the maint UI can show which
|
||||
// agentIds are currently held (and by whom) vs free. Uses SCAN, not
|
||||
// KEYS, to avoid blocking Redis on workspaces with many keys.
|
||||
async listLockedSessions(): Promise<Array<{ agentId: string; memberId: string; ip: string; lockedAt: string }>> {
|
||||
const out: Array<{ agentId: string; memberId: string; ip: string; lockedAt: string }> = [];
|
||||
const stream = this.redis.scanStream({ match: 'agent:session:*', count: 100 });
|
||||
const keys: string[] = [];
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
stream.on('data', (chunk: string[]) => keys.push(...chunk));
|
||||
stream.on('end', resolve);
|
||||
stream.on('error', reject);
|
||||
});
|
||||
for (const key of keys) {
|
||||
const agentId = key.slice('agent:session:'.length);
|
||||
const session = await this.getSession(agentId);
|
||||
if (session) out.push({ agentId, ...session });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Generic cache operations for any module
|
||||
async getCache(key: string): Promise<string | null> {
|
||||
return this.redis.get(key);
|
||||
|
||||
Reference in New Issue
Block a user