chore: ability to group events on redis event bus (#7655)
* chore: ability to group events on redis event bus * chore: fix tests * Update packages/modules/event-bus-redis/src/services/event-bus-redis.ts Co-authored-by: Adrien de Peretti <adrien.deperetti@gmail.com> * chore: change shape of input and body data * chore: fix builds * chore: address comments * chore: fix unit test --------- Co-authored-by: Adrien de Peretti <adrien.deperetti@gmail.com>
This commit is contained in:
1 parent
3b8160b564
commit
39ddba2491
24 files changed
+924
-732
No files matched your search
@@ -35,7 +35,7 @@ export const emitEventStep = createStep(
|
||||
context,
|
||||
})
|
||||
|
||||
await eventBus.emit([message])
|
||||
await eventBus.emit(message)
|
||||
},
|
||||
async (data: void) => {}
|
||||
)
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
EmitData,
|
||||
EventBusTypes,
|
||||
IEventBusModuleService,
|
||||
Message,
|
||||
@@ -7,24 +6,9 @@ import {
|
||||
} from "@medusajs/types"
|
||||
|
||||
export default class EventBusService implements IEventBusModuleService {
|
||||
emit<T>(
|
||||
eventName: string,
|
||||
data: T,
|
||||
options?: Record<string, unknown>
|
||||
): Promise<void>
|
||||
emit<T>(data: EmitData<T>[]): Promise<void>
|
||||
emit<T>(data: Message<T>[]): Promise<void>
|
||||
|
||||
async emit<
|
||||
T,
|
||||
TInput extends
|
||||
| string
|
||||
| EventBusTypes.EmitData<T>[]
|
||||
| EventBusTypes.Message<T>[] = string
|
||||
>(
|
||||
eventOrData: TInput,
|
||||
data?: T,
|
||||
options: Record<string, unknown> = {}
|
||||
async emit<T>(
|
||||
data: Message<T> | Message<T>[],
|
||||
options: Record<string, unknown>
|
||||
): Promise<void> {}
|
||||
|
||||
subscribe(event: string | symbol, subscriber: Subscriber): this {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { initModules, InitModulesOptions } from "./init-modules"
|
||||
import { getDatabaseURL, getMikroOrmWrapper, TestDatabase } from "./database"
|
||||
import { initModules, InitModulesOptions } from "./init-modules"
|
||||
|
||||
import { MockEventBusService } from "."
|
||||
import { ContainerRegistrationKeys, ModulesSdkUtils } from "@medusajs/utils"
|
||||
import { MockEventBusService } from "."
|
||||
|
||||
export interface SuiteOptions<TService = unknown> {
|
||||
MikroOrmWrapper: TestDatabase
|
||||
@@ -75,7 +75,7 @@ export function moduleIntegrationTestRunner<TService = any>({
|
||||
const moduleOptions_: InitModulesOptions = {
|
||||
injectedDependencies: {
|
||||
[ContainerRegistrationKeys.PG_CONNECTION]: connection,
|
||||
["eventBusModuleService"]: new MockEventBusService(),
|
||||
eventBusModuleService: new MockEventBusService(),
|
||||
[ContainerRegistrationKeys.LOGGER]: console,
|
||||
...injectedDependencies,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Context } from "../shared-context"
|
||||
|
||||
export type Subscriber<T = unknown> = (
|
||||
data: T,
|
||||
export type Subscriber<TData = unknown> = (
|
||||
data: TData,
|
||||
eventName: string
|
||||
) => Promise<void>
|
||||
|
||||
@@ -14,36 +14,28 @@ export type SubscriberDescriptor = {
|
||||
subscriber: Subscriber
|
||||
}
|
||||
|
||||
export type EventHandler<T = unknown> = (
|
||||
data: T,
|
||||
export type EventHandler<TData = unknown> = (
|
||||
data: TData,
|
||||
eventName: string
|
||||
) => Promise<void>
|
||||
|
||||
export type EmitData<T = unknown> = {
|
||||
export type EventMetadata = Record<string, unknown> & {
|
||||
eventGroupId?: string
|
||||
}
|
||||
|
||||
export type MessageBody<TData = unknown> = {
|
||||
eventName: string
|
||||
data: T
|
||||
metadata?: EventMetadata
|
||||
data: TData
|
||||
}
|
||||
|
||||
export type Message<TData = unknown> = MessageBody<TData> & {
|
||||
options?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type MessageBody<T = unknown> = {
|
||||
metadata: {
|
||||
source: string
|
||||
action: string
|
||||
object: string
|
||||
eventGroupId?: string
|
||||
}
|
||||
data: T
|
||||
}
|
||||
|
||||
export type Message<T = unknown> = {
|
||||
export type RawMessageFormat<TData = any> = {
|
||||
eventName: string
|
||||
body: MessageBody<T>
|
||||
options?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type RawMessageFormat<T = any> = {
|
||||
eventName: string
|
||||
data: T
|
||||
data: TData
|
||||
source: string
|
||||
object: string
|
||||
action?: string
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { EmitData, Message, Subscriber, SubscriberContext } from "./common"
|
||||
import { Message, Subscriber, SubscriberContext } from "./common"
|
||||
|
||||
export interface IEventBusModuleService {
|
||||
emit<T>(
|
||||
eventName: string,
|
||||
data: T,
|
||||
data: Message<T> | Message<T>[],
|
||||
options?: Record<string, unknown>
|
||||
): Promise<void>
|
||||
emit<T>(data: EmitData<T>[]): Promise<void>
|
||||
emit<T>(data: Message<T>[]): Promise<void>
|
||||
|
||||
subscribe(
|
||||
eventName: string | symbol,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ITransactionBaseService } from "../transaction-base"
|
||||
import { EmitData, Message, Subscriber, SubscriberContext } from "./common"
|
||||
import { Message, Subscriber, SubscriberContext } from "./common"
|
||||
|
||||
export interface IEventBusService extends ITransactionBaseService {
|
||||
subscribe(
|
||||
@@ -14,7 +14,5 @@ export interface IEventBusService extends ITransactionBaseService {
|
||||
context?: SubscriberContext
|
||||
): this
|
||||
|
||||
emit<T>(event: string, data: T, options?: unknown): Promise<unknown | void>
|
||||
emit<T>(data: EmitData<T>[]): Promise<unknown | void>
|
||||
emit<T>(data: Message<T>[]): Promise<unknown | void>
|
||||
emit<T>(data: Message<T> | Message<T>[]): Promise<unknown | void>
|
||||
}
|
||||
@@ -9,70 +9,60 @@ describe("MessageAggregator", function () {
|
||||
const aggregator = new MessageAggregator()
|
||||
aggregator.save({
|
||||
eventName: "ProductVariant.created",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 999 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 999 },
|
||||
})
|
||||
aggregator.save({
|
||||
eventName: "Product.created",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "Product",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 1 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "Product",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 1 },
|
||||
})
|
||||
aggregator.save({
|
||||
eventName: "ProductVariant.created",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 222 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 222 },
|
||||
})
|
||||
aggregator.save({
|
||||
eventName: "ProductType.detached",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "detached",
|
||||
object: "ProductType",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 333 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "detached",
|
||||
object: "ProductType",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 333 },
|
||||
})
|
||||
aggregator.save({
|
||||
eventName: "ProductVariant.updated",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "updated",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 123 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "updated",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 123 },
|
||||
})
|
||||
|
||||
const format = {
|
||||
groupBy: ["eventName", "body.metadata.object", "body.metadata.action"],
|
||||
groupBy: ["eventName", "metadata.object", "metadata.action"],
|
||||
sortBy: {
|
||||
"body.metadata.object": ["ProductType", "ProductVariant", "Product"],
|
||||
"body.data.id": "asc",
|
||||
"metadata.object": ["ProductType", "ProductVariant", "Product"],
|
||||
"data.id": "asc",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -85,72 +75,62 @@ describe("MessageAggregator", function () {
|
||||
expect(allGroups[0]).toEqual([
|
||||
{
|
||||
eventName: "ProductType.detached",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "detached",
|
||||
object: "ProductType",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 333 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "detached",
|
||||
object: "ProductType",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 333 },
|
||||
},
|
||||
])
|
||||
|
||||
expect(allGroups[1]).toEqual([
|
||||
{
|
||||
eventName: "ProductVariant.updated",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "updated",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 123 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "updated",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 123 },
|
||||
},
|
||||
])
|
||||
|
||||
expect(allGroups[2]).toEqual([
|
||||
{
|
||||
eventName: "ProductVariant.created",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 222 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 222 },
|
||||
},
|
||||
{
|
||||
eventName: "ProductVariant.created",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 999 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "ProductVariant",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 999 },
|
||||
},
|
||||
])
|
||||
|
||||
expect(allGroups[3]).toEqual([
|
||||
{
|
||||
eventName: "Product.created",
|
||||
body: {
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "Product",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 1 },
|
||||
metadata: {
|
||||
source: "ProductService",
|
||||
action: "created",
|
||||
object: "Product",
|
||||
eventGroupId: "1",
|
||||
},
|
||||
data: { id: 1 },
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
@@ -45,10 +45,8 @@ export function composeMessage(
|
||||
|
||||
return {
|
||||
eventName,
|
||||
body: {
|
||||
metadata,
|
||||
data,
|
||||
},
|
||||
metadata,
|
||||
data,
|
||||
options,
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,9 @@ export abstract class AbstractEventBusModuleService
|
||||
}
|
||||
|
||||
abstract emit<T>(
|
||||
eventName: string,
|
||||
data: T,
|
||||
data: EventBusTypes.Message<T> | EventBusTypes.Message<T>[],
|
||||
options: Record<string, unknown>
|
||||
): Promise<void>
|
||||
abstract emit<T>(data: EventBusTypes.EmitData<T>[]): Promise<void>
|
||||
abstract emit<T>(data: EventBusTypes.Message<T>[]): Promise<void>
|
||||
|
||||
/*
|
||||
Grouped events are useful when you have distributed transactions
|
||||
|
||||
@@ -501,6 +501,7 @@ export function abstractModuleServiceFactory<
|
||||
await this.eventBusModuleService_?.emit(
|
||||
softDeletedEntities.map(({ id }) => ({
|
||||
eventName: `${kebabCase(model.name)}.deleted`,
|
||||
metadata: { source: "", action: "", object: "" },
|
||||
data: { id },
|
||||
}))
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user