Node.js 在上一个作业完成之前,不要处理下一个作业(Redis?)
基本上,每个客户机(具有与其关联的Node.js 在上一个作业完成之前,不要处理下一个作业(Redis?),node.js,typescript,redis,Node.js,Typescript,Redis,基本上,每个客户机(具有与其关联的clientId)都可以推送消息,重要的是,在第一条消息完成处理之前,不会处理来自同一客户机的第二条消息(即使客户端可以连续发送多条消息,并且它们是有序的,并且发送消息的多个客户端在理想情况下不应该相互干扰)。而且,重要的是,一个作业不应该被处理两次 我认为使用Redis可能会解决这个问题,我开始使用bull库进行一些快速原型设计,但我显然做得不好,我希望有人知道如何进行 这就是我迄今为止所尝试的: 使用clientId作为作业名称,为一个进程创建作业并将其添加
clientId
)都可以推送消息,重要的是,在第一条消息完成处理之前,不会处理来自同一客户机的第二条消息(即使客户端可以连续发送多条消息,并且它们是有序的,并且发送消息的多个客户端在理想情况下不应该相互干扰)。而且,重要的是,一个作业不应该被处理两次
我认为使用Redis可能会解决这个问题,我开始使用bull库进行一些快速原型设计,但我显然做得不好,我希望有人知道如何进行
这就是我迄今为止所尝试的:
clientId
作为作业名称,为一个进程创建作业并将其添加到相同的队列名称中bull
)提供的默认锁定,但它锁定在jobId上,该ID对于每个作业都是唯一的,而不是在clientId上- 在前一个消费者完成处理之前,其中一个消费者无法从同一
接受作业clientId
- 但是,他们应该能够并行地(异步地)从不同的
s获取项目。(我还没有做到这一点,我现在只处理一个clientId
)clientId
- 两个消费者都从队列中消费尽可能多的项目,而无需等待前一个项目完成
clientId
npx ts node consume.ts&
npx ts node consume.ts&
npx ts node create.ts&
我不熟悉node.js。但对于Redis,我会试试这个
假设你有客户端1,客户端2,它们都是事件的发布者。
你有三台机器,消费者1,消费者2,消费者3
这样,每个客户端(任务生产者)的任务按其输入顺序进行处理。如果没有人有更好的主意:如果您有n个消费者,您需要编写1个调度程序来侦听队列,将cleintId散列为n个不同的名称,推送命名的作业,每个消费者都会在作业上侦听其名称……谢谢,尽管我必须说这比我想象的要复杂然而,问题是,我理解你的描述的方式,似乎如果锁已经获得,你将作业放在左侧,因此客户端1作业将按顺序处理,这是我的要求中的一个重要部分。我没有理解吗?也许我没有理解,但每个消费者都需要迭代hr通过此解决方案中的所有
clientId
s,因为如果您从正在迭代的列表中删除clientId
,则如果另一个进程正在删除client\u names\u list
列表,则访问消息时可能会出现问题。对吗?是的,每个消费者都需要迭代所有clientId。它从客户端名称列表
只保留客户端的所有ID,为什么要删除它?如果要删除客户端,首先需要检查此客户端的任务列表是否为空(所有任务都已完成)
// ./setup.ts
import Queue from 'bull';
import * as uuid from 'uuid';
// Check that when a message is taken from a place, no other message is taken
// TO do that test, have two processes that process messages and one that sets messages, and make the job take a long time
// queue for each room https://stackoverflow.com/questions/54178462/how-does-redis-pubsub-subscribe-mechanism-works/54243792#54243792
// https://groups.google.com/forum/#!topic/redis-db/R09u__3Jzfk
// Make a job not be called stalled, waiting enough time https://github.com/OptimalBits/bull/issues/210#issuecomment-190818353
export async function sleep(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
export interface JobData {
id: string;
v: number;
}
export const queue = new Queue<JobData>('messages', 'redis://127.0.0.1:6379');
queue.on('error', (err) => {
console.error('Uncaught error on queue.', err);
process.exit(1);
});
export function clientId(): string {
return uuid.v4();
}
export function randomWait(minms: number, maxms: number): Promise<void> {
const ms = Math.random() * (maxms - minms) + minms;
return sleep(ms);
}
// Make a job not be called stalled, waiting enough time https://github.com/OptimalBits/bull/issues/210#issuecomment-190818353
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
queue.LOCK_RENEW_TIME = 5 * 60 * 1000;
// ./create.ts
import { queue, randomWait } from './setup';
const MIN_WAIT = 300;
const MAX_WAIT = 1500;
async function createJobs(n = 10): Promise<void> {
await randomWait(MIN_WAIT, MAX_WAIT);
// always same Id
const clientId = Math.random() > 1 ? 'zero' : 'one';
for (let index = 0; index < n; index++) {
await randomWait(MIN_WAIT, MAX_WAIT);
const job = { id: clientId, v: index };
await queue.add(clientId, job).catch(console.error);
console.log('Added job', job);
}
}
export async function create(nIds = 10, nItems = 10): Promise<void> {
const jobs = [];
await randomWait(MIN_WAIT, MAX_WAIT);
for (let index = 0; index < nIds; index++) {
await randomWait(MIN_WAIT, MAX_WAIT);
jobs.push(createJobs(nItems));
await randomWait(MIN_WAIT, MAX_WAIT);
}
await randomWait(MIN_WAIT, MAX_WAIT);
await Promise.all(jobs)
process.exit();
}
(function mainCreate(): void {
create().catch((err) => {
console.error(err);
process.exit(1);
});
})();
// ./consume.ts
import { queue, randomWait, clientId } from './setup';
function startProcessor(minWait = 5000, maxWait = 10000): void {
queue
.process('*', 100, async (job) => {
console.log('LOCKING: ', job.lockKey());
await job.takeLock();
const name = job.name;
const processingId = clientId().split('-', 1)[0];
try {
console.log('START: ', processingId, '\tjobName:', name);
await randomWait(minWait, maxWait);
const data = job.data;
console.log('PROCESSING: ', processingId, '\tjobName:', name, '\tdata:', data);
await randomWait(minWait, maxWait);
console.log('PROCESSED: ', processingId, '\tjobName:', name, '\tdata:', data);
await randomWait(minWait, maxWait);
console.log('FINISHED: ', processingId, '\tjobName:', name, '\tdata:', data);
} catch (err) {
console.error(err);
} finally {
await job.releaseLock();
}
})
.catch(console.error); // Catches initialization
}
startProcessor();