我有3个使用网络套接字交换消息的nodejs服务。
第一个服务通过Web套接字将事件发送到第二个服务。第二个服务负责详细说明事件并将它们保存在mongodb数据库上,一旦事件已保存在数据库上,第二个服务就将详细事件发送到第三个服务(gui),始终使用Web套接字。
这是从第一个接收事件的第二个服务的代码:
this.socketClient.on('NEW_EVENT', (event: MyEvent) => {
winston.info(`[newEvent] New Event received: %s`, event.type);
console.log('0__', event.payload);
// Search for the right class that can handle the specific event
for (const handler of this.handlers) {
if (handler.isApplicable(event.type)) {
// Handler found
handler.handle(event).then((handledEvent) => {
console.log('1__', handledEvent);
// Send the handled event to the gui
this.webSockerService.publishNewEvent(event.type, handledEvent);
});
return;
}
}
});
这是Handler的代码,负责处理一个特定事件(在这种情况下,它只是调用正确的服务来处理事件):
public async handle(event: Event): Promise<Component> {
winston.info('[ComponentHandler:handle]');
return this.componentService
.componentStatusChanged(event.header.sender, event.header.senderType, event.payload);
}
这是我的componentService类的代码(在这个特定的情况下,它只使用负责将数据库中的事件保存的正确的存储库)
public async componentStatusChanged(componentId: string, componentType: ComponentType, componentStatus: ComponentStatus): Promise<any> {
return this.componentRepository
.componentStatusChanged(componentId, componentType, componentStatus);
}
这是我的componentRepository的代码:
public async componentStatusChanged(componentId: string, componentType: ComponentType, componentStatus: ComponentStatus): Promise<Component> {
winston.info('[ComponentRepository::componentStatusChanged] Component %s newStatus %s', componentId, componentStatus);
try {
await this.fetch({ name: componentId });
return this.update(componentId, { status: componentStatus });
} catch (ex) {
// Component not exists
const newComponent: Component = {
name: componentId,
type: componentType,
status: componentStatus,
updatedAt: new Date().getTime()
};
return this.newComponent(newComponent);
}
}
public async update(componentId: string, newValues: any): Promise<Component> {
winston.info('[ComponentRepository::update] Updating component %s. New Values: %j', componentId, newValues);
await this.component.get().update({ name: componentId }, newValues);
return this.fetch({ name: componentId });
}
public async newComponent(component: Component): Promise<Component> {
winston.info('[ComponentRepository::newComponent] Creating Component %j', component);
return this.component.get().create(component);
}
public async fetch(filter: any): Promise<Component> {
winston.info('[ComponentRepository::fetch] component %j', filter);
return this.component.get().findOne(filter);
}
问题是第二个服务以正确的顺序接收事件,但它会在一些日志之后将它们转发给错误的gui:
第二个组件收到的事件有效负载:STARTED - &gt;分析 - &gt;聆听 - &gt;分析 - &gt;聆听 - &gt;分析 - &gt;聆听......
正如您在日志中看到的那样,console.log('0__...)
打印的事件的顺序与console.log('1___....)
info: [newEvent] New Event received: STATUS
0___ STARTED
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus STARTED
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ ANALYZING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ LISTENING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"ANALYZING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"STARTED"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"LISTENING"}
info: [newEvent] New Event received: STATUS
0___ ANALYZING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ LISTENING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ ANALYZING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ LISTENING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ ANALYZING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ LISTENING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ ANALYZING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ LISTENING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ ANALYZING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ LISTENING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ ANALYZING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"ANALYZING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"LISTENING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"LISTENING"}
info: [newEvent] New Event received: STATUS
0___ LISTENING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ ANALYZING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [newEvent] New Event received: STATUS
0___ LISTENING
info: [ComponentHandler:handle]
info: [ComponentRepository::componentStatusChanged] Component auth.srv newStatus LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"LISTENING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"ANALYZING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"LISTENING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"ANALYZING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"ANALYZING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"ANALYZING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"LISTENING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"ANALYZING"}
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"ANALYZING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"LISTENING"}
info: [ComponentRepository::update] Updating component auth.srv. New Values: {"status":"LISTENING"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'ANALYZING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS ANALYZING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'ANALYZING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'ANALYZING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS ANALYZING
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
info: [ComponentRepository::fetch] component {"name":"auth.srv"}
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING
1____ { _id: 5af470ae8278f6320b3a00f3,
name: 'auth.srv',
type: 'AUTH_SERVICE',
status: 'LISTENING',
updatedAt: 1525969070608,
__v: 0 }
info: [WebSocketService::publishNewEvent] type: STATUS LISTENING'
修改
当我使用WebSockets时,似乎有某种竞争条件。我试图单独测试我的组件,没有问题。只要我使用websockets并快速重复发布事件,就会在回调堆栈上发生一些事情。 如何按正确的顺序处理事件?问题似乎是当我尝试在mongodb上进行I / O操作时。 谢谢
答案 0 :(得分:0)
我解决了创建单独处理的事件队列的问题。
如果您有更好的解决方案,请在此处发布。
constructor() {
setInterval(async () => {
if (this.newEvents.length > 0) {
await this.handleNewEvents();
}
}, 50);
}
this.socketClient.on('NEW_EVENT', (event: MyEvent) => {
this.newEvents.push(event);
});
private async handleNewEvents(): Promise<any> {
const event = this.newEvents.shift();
await this.handleEvent(event);
if (this.newEvents.length > 0) {
await this.handleNewEvents();
}
}
private async handleEvent(event: Event): Promise<any> {
return new Promise((resolve, reject) => {
for (const handler of this.handlers) {
if (handler.isApplicable(event.type)) {
handler.handle(event).then((handledEvent) => {
this.webSockerService.publishNewEvent(event.type, handledEvent);
resolve();
});
return;
}
}
winston.error('Handler not found for %s ', event.type);
reject();
});
}
}