mirror of
https://github.com/fosrl/pangolin.git
synced 2026-10-29 15:09:07 +01:00
Improve latency on register messages for olm
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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})`
|
||||
|
||||
Reference in New Issue
Block a user