chore(event-bus-*): Do not emit if no subscribers: (#14084)
* chore(event-vus-*): Do not emit if no subscribers: * Create curly-apricots-double.md * add tests * align tests
This commit is contained in:
@@ -26,13 +26,21 @@ describe("LocalEventBusService", () => {
|
||||
})
|
||||
|
||||
it("should emit an event", async () => {
|
||||
eventBus.subscribe("eventName", () => Promise.resolve())
|
||||
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn((event) =>
|
||||
event === "eventName" ? 1 : 0
|
||||
)
|
||||
|
||||
await eventBus.emit({
|
||||
name: "eventName",
|
||||
data: { hi: "1234" },
|
||||
})
|
||||
|
||||
// Wait for async emission to complete
|
||||
await new Promise((resolve) => setImmediate(resolve))
|
||||
|
||||
expect(eventEmitter.emit).toHaveBeenCalledTimes(1)
|
||||
expect(eventEmitter.emit).toHaveBeenCalledWith("eventName", {
|
||||
data: { hi: "1234" },
|
||||
@@ -41,12 +49,17 @@ describe("LocalEventBusService", () => {
|
||||
|
||||
expect(loggerMock.info).toHaveBeenCalledTimes(1)
|
||||
expect(loggerMock.info).toHaveBeenCalledWith(
|
||||
"Processing eventName which has undefined subscribers"
|
||||
"Processing eventName which has 1 subscribers"
|
||||
)
|
||||
})
|
||||
|
||||
it("should emit an event but not log anything if it is internal", async () => {
|
||||
eventBus.subscribe("eventName", () => Promise.resolve())
|
||||
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn((event) =>
|
||||
event === "eventName" ? 1 : 0
|
||||
)
|
||||
|
||||
await eventBus.emit({
|
||||
name: "eventName",
|
||||
@@ -56,6 +69,9 @@ describe("LocalEventBusService", () => {
|
||||
},
|
||||
})
|
||||
|
||||
// Wait for async emission to complete
|
||||
await new Promise((resolve) => setImmediate(resolve))
|
||||
|
||||
expect(eventEmitter.emit).toHaveBeenCalledTimes(1)
|
||||
expect(eventEmitter.emit).toHaveBeenCalledWith("eventName", {
|
||||
data: { hi: "1234" },
|
||||
@@ -74,6 +90,9 @@ describe("LocalEventBusService", () => {
|
||||
}
|
||||
)
|
||||
|
||||
// Wait for async emission to complete
|
||||
await new Promise((resolve) => setImmediate(resolve))
|
||||
|
||||
expect(eventEmitter.emit).toHaveBeenCalledTimes(2)
|
||||
expect(eventEmitter.emit).toHaveBeenCalledWith("eventName", {
|
||||
data: { hi: "1234" },
|
||||
@@ -84,13 +103,22 @@ describe("LocalEventBusService", () => {
|
||||
})
|
||||
|
||||
it("should emit multiple events", async () => {
|
||||
eventBus.subscribe("event-1", () => Promise.resolve())
|
||||
eventBus.subscribe("event-2", () => Promise.resolve())
|
||||
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn((event) =>
|
||||
event === "event-1" || event === "event-2" ? 1 : 0
|
||||
)
|
||||
|
||||
await eventBus.emit([
|
||||
{ name: "event-1", data: { hi: "1234" } },
|
||||
{ name: "event-2", data: { hi: "5678" } },
|
||||
])
|
||||
|
||||
// Wait for async emission to complete
|
||||
await new Promise((resolve) => setImmediate(resolve))
|
||||
|
||||
expect(eventEmitter.emit).toHaveBeenCalledTimes(2)
|
||||
expect(eventEmitter.emit).toHaveBeenCalledWith("event-1", {
|
||||
data: { hi: "1234" },
|
||||
@@ -161,7 +189,13 @@ describe("LocalEventBusService", () => {
|
||||
})
|
||||
|
||||
it("should release events when requested with eventGroupId", async () => {
|
||||
eventBus.subscribe("event-1", () => Promise.resolve())
|
||||
eventBus.subscribe("event-2", () => Promise.resolve())
|
||||
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn((event) =>
|
||||
event === "event-1" || event === "event-2" ? 1 : 0
|
||||
)
|
||||
|
||||
await eventBus.emit([
|
||||
{
|
||||
@@ -187,6 +221,9 @@ describe("LocalEventBusService", () => {
|
||||
{ name: "event-1", data: { test: "1" } },
|
||||
])
|
||||
|
||||
// Wait for async emission to complete
|
||||
await new Promise((resolve) => setImmediate(resolve))
|
||||
|
||||
expect(eventEmitter.emit).toHaveBeenCalledTimes(1)
|
||||
expect(eventEmitter.emit).toHaveBeenCalledWith("event-1", {
|
||||
data: { test: "1" },
|
||||
@@ -204,6 +241,9 @@ describe("LocalEventBusService", () => {
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
await eventBus.releaseGroupedEvents("group-1")
|
||||
|
||||
// Wait for async emission to complete
|
||||
await new Promise((resolve) => setImmediate(resolve))
|
||||
|
||||
expect(
|
||||
(eventBus as any).groupedEventsMap_.get("group-1")
|
||||
).not.toBeDefined()
|
||||
@@ -254,5 +294,139 @@ describe("LocalEventBusService", () => {
|
||||
expect(getMap().get("group-2")).not.toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("Events without subscribers", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
eventBus = new LocalEventBusService(moduleDeps as any, {}, {} as any)
|
||||
eventEmitter = (eventBus as any).eventEmitter_
|
||||
})
|
||||
|
||||
it("should not emit events when there are no subscribers", async () => {
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn(() => 0)
|
||||
|
||||
await eventBus.emit({
|
||||
name: "eventWithoutSubscribers",
|
||||
data: { test: "data" },
|
||||
})
|
||||
|
||||
expect(eventEmitter.emit).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should still call interceptors even when there are no subscribers", async () => {
|
||||
const callInterceptorsSpy = jest.spyOn(
|
||||
eventBus as any,
|
||||
"callInterceptors"
|
||||
)
|
||||
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn(() => 0)
|
||||
|
||||
await eventBus.emit({
|
||||
name: "eventWithoutSubscribers",
|
||||
data: { test: "data" },
|
||||
})
|
||||
|
||||
expect(callInterceptorsSpy).toHaveBeenCalledTimes(1)
|
||||
expect(callInterceptorsSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
name: "eventWithoutSubscribers",
|
||||
data: { test: "data" },
|
||||
}),
|
||||
{ isGrouped: false }
|
||||
)
|
||||
|
||||
expect(eventEmitter.emit).not.toHaveBeenCalled()
|
||||
|
||||
callInterceptorsSpy.mockRestore()
|
||||
})
|
||||
|
||||
it("should emit events with wildcard subscriber", async () => {
|
||||
eventBus.subscribe("*", () => Promise.resolve())
|
||||
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn((event) => (event === "*" ? 1 : 0))
|
||||
|
||||
await eventBus.emit({
|
||||
name: "anyEvent",
|
||||
data: { test: "data" },
|
||||
})
|
||||
|
||||
// Wait for async emission to complete
|
||||
await new Promise((resolve) => setImmediate(resolve))
|
||||
|
||||
expect(eventEmitter.emit).toHaveBeenCalledTimes(1)
|
||||
expect(eventEmitter.emit).toHaveBeenCalledWith("*", {
|
||||
data: { test: "data" },
|
||||
name: "anyEvent",
|
||||
})
|
||||
})
|
||||
|
||||
it("should not emit grouped events when releasing if there are no subscribers", async () => {
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn(() => 0)
|
||||
|
||||
await eventBus.emit({
|
||||
name: "grouped-event-no-sub",
|
||||
data: { hi: "1234" },
|
||||
metadata: { eventGroupId: "test-group-no-sub" },
|
||||
})
|
||||
|
||||
expect(
|
||||
(eventBus as any).groupedEventsMap_.get("test-group-no-sub")
|
||||
).toHaveLength(1)
|
||||
expect(eventEmitter.emit).not.toHaveBeenCalled()
|
||||
|
||||
jest.clearAllMocks()
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
|
||||
await eventBus.releaseGroupedEvents("test-group-no-sub")
|
||||
|
||||
expect(eventEmitter.emit).not.toHaveBeenCalled()
|
||||
|
||||
expect(
|
||||
(eventBus as any).groupedEventsMap_.get("test-group-no-sub")
|
||||
).not.toBeDefined()
|
||||
})
|
||||
|
||||
it("should still call interceptors for grouped events without subscribers", async () => {
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
eventEmitter.listenerCount = jest.fn(() => 0)
|
||||
|
||||
await eventBus.emit({
|
||||
name: "grouped-event-no-sub-2",
|
||||
data: { hi: "1234" },
|
||||
metadata: { eventGroupId: "test-group-no-sub-2" },
|
||||
})
|
||||
|
||||
expect(
|
||||
(eventBus as any).groupedEventsMap_.get("test-group-no-sub-2")
|
||||
).toHaveLength(1)
|
||||
|
||||
jest.clearAllMocks()
|
||||
eventEmitter.emit = jest.fn((data) => data)
|
||||
|
||||
const callInterceptorsSpy = jest.spyOn(
|
||||
eventBus as any,
|
||||
"callInterceptors"
|
||||
)
|
||||
|
||||
await eventBus.releaseGroupedEvents("test-group-no-sub-2")
|
||||
|
||||
expect(callInterceptorsSpy).toHaveBeenCalledTimes(1)
|
||||
expect(callInterceptorsSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
name: "grouped-event-no-sub-2",
|
||||
}),
|
||||
{ isGrouped: true, eventGroupId: "test-group-no-sub-2" }
|
||||
)
|
||||
|
||||
expect(eventEmitter.emit).not.toHaveBeenCalled()
|
||||
|
||||
callInterceptorsSpy.mockRestore()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -58,11 +58,6 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
|
||||
const eventListenersCount = this.eventEmitter_.listenerCount(
|
||||
eventData.name
|
||||
)
|
||||
const startSubscribersCount = this.eventEmitter_.listenerCount("*")
|
||||
|
||||
if (eventListenersCount === 0 && startSubscribersCount === 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!options.internal && !eventData.options?.internal) {
|
||||
this.logger_?.info(
|
||||
@@ -93,11 +88,18 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
|
||||
const options_ = eventData.options as { delay: number }
|
||||
const delay = (ms?: number) => (ms ? setTimeout(ms) : Promise.resolve())
|
||||
|
||||
const eventListenersCount = this.eventEmitter_.listenerCount(
|
||||
eventData.name
|
||||
)
|
||||
|
||||
delay(options_?.delay).then(async () => {
|
||||
// Call interceptors before emitting
|
||||
void this.callInterceptors(eventData, { isGrouped: false })
|
||||
|
||||
this.eventEmitter_.emit(eventData.name, eventBody)
|
||||
if (eventListenersCount) {
|
||||
this.eventEmitter_.emit(eventData.name, eventBody)
|
||||
}
|
||||
|
||||
if (hasStarSubscriber) {
|
||||
this.eventEmitter_.emit("*", eventBody)
|
||||
}
|
||||
@@ -120,11 +122,14 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
|
||||
async releaseGroupedEvents(eventGroupId: string) {
|
||||
let groupedEvents = this.groupedEventsMap_.get(eventGroupId) || []
|
||||
groupedEvents = JSON.parse(JSON.stringify(groupedEvents))
|
||||
|
||||
const hasStarSubscriber = this.eventEmitter_.listenerCount("*") > 0
|
||||
|
||||
for (const event of groupedEvents) {
|
||||
const { options, ...eventBody } = event
|
||||
|
||||
const eventListenersCount = this.eventEmitter_.listenerCount(event.name)
|
||||
|
||||
const options_ = options as { delay: number }
|
||||
const delay = (ms?: number) => (ms ? setTimeout(ms) : Promise.resolve())
|
||||
|
||||
@@ -132,7 +137,10 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
|
||||
// Call interceptors before emitting grouped events
|
||||
void this.callInterceptors(event, { isGrouped: true, eventGroupId })
|
||||
|
||||
this.eventEmitter_.emit(event.name, eventBody)
|
||||
if (eventListenersCount) {
|
||||
this.eventEmitter_.emit(event.name, eventBody)
|
||||
}
|
||||
|
||||
if (hasStarSubscriber) {
|
||||
this.eventEmitter_.emit("*", eventBody)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user