Skip to main content

queueByKey()

queueByKey<T>(key, fn): Promise<T>

Queues async functions by key to ensure sequential execution.

๐Ÿ’Ž Why is this a Hidden Gem?

Ensures sequential execution by key. Prevents race conditions by forcing operations to run one after another.

note

Functions with the same key execute sequentially. Different keys run in parallel.


Type Parametersโ€‹

T: Tโ€‹

The return type of the function.


Parametersโ€‹

key: stringโ€‹

Unique key for the operation queue.

fn: () => Promise<T>โ€‹

The async function to queue.


Returns: Promise<T>โ€‹

Promise that resolves to the function result.


Throwsโ€‹

Rejects if the queued function rejects.


See Alsoโ€‹

dedupeByKey โ€” for deduplication instead of queuing.


Sinceโ€‹

1.1.0


Performanceโ€‹

Silently catches errors to prevent queue breakage; errors still propagate to caller.


Also known asโ€‹

Queue (Modern Dash) ยท queueByKey (Radashi) ยท โŒ (Lodash, es-toolkit, Remeda, Ramda, Effect, Antfu)


Exampleโ€‹

// Sequential execution for same key
queueByKey('user-123', () => updateUser('123'));
queueByKey('user-123', () => updateUser('123'));
// Second waits for first to complete

// Parallel execution for different keys
queueByKey('user-A', () => updateUser('A'));
queueByKey('user-B', () => updateUser('B'));

How it works?โ€‹

Ensures sequential execution for functions sharing the same key. Different keys run in parallel โ€” same key waits for previous to complete.

Queue vs Dedupeโ€‹

queueByKeydedupeByKey
Same key callsSequentialShared
ResultEach gets ownSame promise
Use caseOrdered writesDuplicate reads

Use Casesโ€‹

Sequential Database Writes ๐Ÿ“Œโ€‹

Ensure that updates to the same record happen strictly in order, preventing "Lost Update" anomalies. Essential for counters, inventory management, or financial balances.

// Safe inventory update
const decrementStock = async (productId: string) => {
return await queueByKey(`stock-${productId}`, async () => {
const current = await db.getStock(productId);
if (current > 0) {
await db.updateStock(productId, current - 1);
}
});
};

// Even if called in parallel, updates will run one after another
await Promise.all([
decrementStock("item-1"),
decrementStock("item-1"),
decrementStock("item-1")
]);
// Stock decreases by 3 correctly

Prevent File Corruptionโ€‹

When appending to a file or updating a shared local resource, ensure only one write happens at a time.

// Safe log appending
const writeLog = async (message: string) => {
await queueByKey('system-log', async () => {
const timestamp = new Date().toISOString();
await fs.appendFile('system.log', `[${timestamp}] ${message}\n`);
});
};

Ordered message processingโ€‹

Process messages for the same conversation in strict order. Essential for chat apps, event sourcing, or command queues.

const processMessage = async (conversationId: string, message: Message) => {
return await queueByKey(`conv-${conversationId}`, async () => {
// Messages for same conversation processed in order
await db.insertMessage(message);
await updateConversationTimestamp(conversationId);
await notifyParticipants(conversationId, message);
});
};

// Even if messages arrive out of order from WebSocket
socket.on("message", (msg) => {
processMessage(msg.conversationId, msg);
});
// Each conversation's messages are processed sequentially