Improve latency on register messages for olm

This commit is contained in:
Owen
2026-10-22 16:04:38 -04:00
parent 290f1f2ff0
commit 5ff8ecdf78
9 changed files with 224 additions and 80 deletions
+36
View File
@@ -17,6 +17,9 @@ import { v4 as uuidv4 } from "uuid";
const instanceId = uuidv4();
// Max keys passed to a single EXISTS call in anyLockExists
const LOCK_EXISTS_CHUNK_SIZE = 1000;
type LocalLockRecord = {
owner: string;
expiresAt: number;
@@ -254,6 +257,39 @@ export class LockManager {
}
}
/**
* Check whether any of the given locks currently exist, using one EXISTS
* call per chunk of keys instead of a round trip per key
* @param lockKeys - Unique identifiers for the locks
* @returns Promise<boolean> - true if at least one lock is held
*/
async anyLockExists(lockKeys: string[]): Promise<boolean> {
if (!redis || !redis.status || redis.status !== "ready") {
for (const lockKey of lockKeys) {
this.clearExpiredLocalLock(lockKey);
if (localLocks.has(lockKey)) {
return true;
}
}
return false;
}
try {
for (let i = 0; i < lockKeys.length; i += LOCK_EXISTS_CHUNK_SIZE) {
const redisKeys = lockKeys
.slice(i, i + LOCK_EXISTS_CHUNK_SIZE)
.map((lockKey) => `lock:${lockKey}`);
if ((await redis.exists(...redisKeys)) > 0) {
return true;
}
}
return false;
} catch (error) {
logger.error("Failed to check lock existence:", error);
return false;
}
}
/**
* Extend the TTL of an existing lock, provided the token matches the
* acquisition currently holding it.
+18
View File
@@ -66,6 +66,24 @@ class RedisRebuildQueue {
}
}
// Pipelines the membership checks so any number of jobs costs one round trip
async anyQueued(jobs: RebuildJob[]): Promise<boolean> {
if (jobs.length === 0) return false;
if (!redis || redis.status !== "ready") return false;
try {
const pipeline = redis.pipeline();
for (const job of jobs) {
pipeline.sismember(QUEUED_SET_KEY, `${job.type}:${job.id}`);
}
const results = await pipeline.exec();
return (results ?? []).some(
([err, member]) => !err && member === 1
);
} catch {
return false;
}
}
async enqueue(job: RebuildJob): Promise<void> {
if (!redis || redis.status !== "ready") {
logger.warn(
+12 -4
View File
@@ -792,13 +792,21 @@ const sendToClientsBatch = async (
)
);
for (const entry of entries) {
// Issue all increments at once so Redis receives them back to back on one
// connection (in entry order) instead of waiting a round trip per entry
const configVersions = await Promise.all(
entries.map((entry) =>
entry.options?.incrementConfigVersion
? incrementClientConfigVersion(entry.clientId)
: stableConfigVersionByClient.get(entry.clientId)
)
);
for (const [index, entry] of entries.entries()) {
const options = entry.options || {};
const { clientId, message } = entry;
const configVersion = options.incrementConfigVersion
? await incrementClientConfigVersion(clientId)
: stableConfigVersionByClient.get(clientId);
const configVersion = configVersions[index];
logger.debug(
`sendToClientsBatch: Message type ${message.type} queued for clientId ${clientId} (new configVersion: ${configVersion})`