Skip to content

Instantly share code, notes, and snippets.

@u12206050
Last active March 5, 2023 21:23
Show Gist options
  • Save u12206050/8de4bc67b3fb5536e48ce00dffc32707 to your computer and use it in GitHub Desktop.
Save u12206050/8de4bc67b3fb5536e48ce00dffc32707 to your computer and use it in GitHub Desktop.
Debounces the execution of a function being called across containers utilising a shared cache
// eslint-disable-next-line node/no-extraneous-import
import Keyv from 'keyv';
/**
* Debounces the execution of a function that takes an ID parameter, ensuring that it only runs once per second
* for each ID across all containers/threads. Uses a combination of shared cache and a locking mechanism to achieve this.
*
* @param id - The ID parameter for the function being debounced
* @param cache - The Redis cache instance used for locking and storing timestamps
* @param fn - The function being debounced, which takes the ID parameter and returns a Promise
* @param delay - The delay in milliseconds between each execution of the function
*/
export async function safeDebounce(
id: string | number,
cache: Keyv,
fn: (id: string | number) => Promise<any>,
delay = 1000,
_added = Date.now()
) {
const lockKey = `lock:${id}`;
const lastAddedKey = `added:${id}`;
// Get the timestamp of the last action for this ID
const latestAdded = await cache.get(lastAddedKey);
if (latestAdded && _added < latestAdded) {
// A newer action has been added, so we can ignore this one
return;
}
await cache.set(lastAddedKey, _added, delay);
// Check if the lock is already set for this ID
const isLocked = await cache.get(lockKey);
if (!isLocked) {
// Set the lock
await cache.set(lockKey, _added, delay);
try {
// Execute the function
return await fn(id);
} catch (e) {
console.error(e);
}
} else {
setTimeout(() => {
safeDebounce(id, cache, fn, delay, _added);
}, delay / 2);
}
}
@u12206050
Copy link
Author

Using with Directus? Any ItemsService has a cache property that currently is Keyv so you can pass that through
eg.

const service = new ItemsService('products', ctx);
await safeDebounce(123, service.cache, myDebounceFn);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment