chore(): Emit events in batch and index process event ids in batch (#12097)

**What**
First iteration to prevent events from overwhelming the systems.
- Group emitted event ids when possible instead of creating a message per id which leads to reduced amount of events to process massively in cases of import for example
- Update the index engine to process event data in batches of 100
- Update event handling by the index engine to be able to upsert by batch as well
- Fix index engine build config for intermediate listeners inferrence
This commit is contained in:
Adrien de Peretti
2025-04-08 16:57:08 +00:00
committed by GitHub
parent b05807bfc1
commit 74381addc3
21 changed files with 548 additions and 463 deletions
@@ -11,6 +11,7 @@ import {
} from "@medusajs/framework/types"
import {
CommonEvents,
EmitEvents,
InjectManager,
InjectTransactionManager,
isDefined,
@@ -18,6 +19,7 @@ import {
MapToConfig,
MedusaContext,
MedusaError,
moduleEventBuilderFactory,
Modules,
ModulesSdkUtils,
} from "@medusajs/framework/utils"
@@ -175,6 +177,7 @@ export default class LinkModuleService implements ILinkModule {
}
@InjectTransactionManager()
@EmitEvents()
async create(
primaryKeyOrBulkData:
| string
@@ -207,18 +210,15 @@ export default class LinkModuleService implements ILinkModule {
const links = await this.linkService_.create(data, sharedContext)
await this.eventBusModuleService_?.emit<Record<string, unknown>>(
(data as { id: unknown }[]).map(({ id }) => ({
name: this.entityName_ + "." + CommonEvents.ATTACHED,
metadata: {
source: this.serviceName_,
action: CommonEvents.ATTACHED,
object: this.entityName_,
eventGroupId: sharedContext.eventGroupId,
},
data: { id },
}))
)
moduleEventBuilderFactory({
action: CommonEvents.ATTACHED,
object: this.entityName_,
source: this.serviceName_,
eventName: this.entityName_ + "." + CommonEvents.ATTACHED,
})({
data: data as { id: string }[],
sharedContext,
})
return (await this.baseRepository_.serialize(links)) as unknown[]
}
@@ -249,6 +249,7 @@ export default class LinkModuleService implements ILinkModule {
}
@InjectTransactionManager()
@EmitEvents()
async delete(
data: any,
@MedusaContext() sharedContext: Context = {}
@@ -258,20 +259,19 @@ export default class LinkModuleService implements ILinkModule {
await this.linkService_.delete(data, sharedContext)
const allData = Array.isArray(data) ? data : [data]
await this.eventBusModuleService_?.emit<Record<string, unknown>>(
allData.map(({ id }) => ({
name: this.entityName_ + "." + CommonEvents.DETACHED,
metadata: {
source: this.serviceName_,
action: CommonEvents.DETACHED,
object: this.entityName_,
eventGroupId: sharedContext.eventGroupId,
},
data: { id },
}))
)
moduleEventBuilderFactory({
action: CommonEvents.DETACHED,
object: this.entityName_,
source: this.serviceName_,
eventName: this.entityName_ + "." + CommonEvents.DETACHED,
})({
data: allData as { id: string }[],
sharedContext,
})
}
@InjectTransactionManager()
@EmitEvents()
async softDelete(
data: any,
{ returnLinkableKeys }: SoftDeleteReturn = {},
@@ -307,18 +307,15 @@ export default class LinkModuleService implements ILinkModule {
)
}
await this.eventBusModuleService_?.emit<Record<string, unknown>>(
(deletedEntities as { id: string }[]).map(({ id }) => ({
name: this.entityName_ + "." + CommonEvents.DETACHED,
metadata: {
source: this.serviceName_,
action: CommonEvents.DETACHED,
object: this.entityName_,
eventGroupId: sharedContext.eventGroupId,
},
data: { id },
}))
)
moduleEventBuilderFactory({
action: CommonEvents.DETACHED,
object: this.entityName_,
source: this.serviceName_,
eventName: this.entityName_ + "." + CommonEvents.DETACHED,
})({
data: deletedEntities as { id: string }[],
sharedContext,
})
return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0
}
@@ -331,6 +328,8 @@ export default class LinkModuleService implements ILinkModule {
return await this.linkService_.softDelete(data, sharedContext)
}
@InjectTransactionManager()
@EmitEvents()
async restore(
data: any,
{ returnLinkableKeys }: RestoreReturn = {},
@@ -365,18 +364,15 @@ export default class LinkModuleService implements ILinkModule {
)
}
await this.eventBusModuleService_?.emit<Record<string, unknown>>(
(restoredEntities as { id: string }[]).map(({ id }) => ({
name: this.entityName_ + "." + CommonEvents.ATTACHED,
metadata: {
source: this.serviceName_,
action: CommonEvents.ATTACHED,
object: this.entityName_,
eventGroupId: sharedContext.eventGroupId,
},
data: { id },
}))
)
moduleEventBuilderFactory({
action: CommonEvents.ATTACHED,
object: this.entityName_,
source: this.serviceName_,
eventName: this.entityName_ + "." + CommonEvents.ATTACHED,
})({
data: restoredEntities as { id: string }[],
sharedContext,
})
return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0
}
@@ -388,4 +384,21 @@ export default class LinkModuleService implements ILinkModule {
): Promise<[object[], Record<string, string[]>]> {
return await this.linkService_.restore(data, sharedContext)
}
protected async emitEvents_(groupedEvents) {
if (!this.eventBusModuleService_ || !groupedEvents) {
return
}
const promises: Promise<void>[] = []
for (const group of Object.keys(groupedEvents)) {
promises.push(
this.eventBusModuleService_.emit(groupedEvents[group], {
internal: true,
})
)
}
await Promise.all(promises)
}
}