Aller au contenu principal

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.

remarque

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