feat(medusa,event-bus-local,event-bus-redis): Event Bus modules (#2599)
This commit is contained in:
1 parent
7408111d11
commit
ef5ef9f5a2
114 files changed
+2423
-1669
No files matched your search
@@ -0,0 +1,6 @@
|
||||
/dist
|
||||
node_modules
|
||||
.DS_store
|
||||
.env*
|
||||
.env
|
||||
*.sql
|
||||
@@ -0,0 +1,63 @@
|
||||
<p align="center">
|
||||
<a href="https://www.medusajs.com">
|
||||
<img alt="Medusa" src="https://user-images.githubusercontent.com/7554214/153162406-bf8fd16f-aa98-4604-b87b-e13ab4baf604.png" width="100" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
@medusajs/event-bus-local
|
||||
</h1>
|
||||
|
||||
<h4 align="center">
|
||||
<a href="https://docs.medusajs.com">Documentation</a> |
|
||||
<a href="https://www.medusajs.com">Website</a>
|
||||
</h4>
|
||||
|
||||
<p align="center">
|
||||
An open source composable commerce engine built for developers.
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/medusajs/medusa/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Medusa is released under the MIT license." />
|
||||
</a>
|
||||
<a href="https://circleci.com/gh/medusajs/medusa">
|
||||
<img src="https://circleci.com/gh/medusajs/medusa.svg?style=shield" alt="Current CircleCI build status." />
|
||||
</a>
|
||||
<a href="https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md">
|
||||
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" alt="PRs welcome!" />
|
||||
</a>
|
||||
<a href="https://www.producthunt.com/posts/medusa"><img src="https://img.shields.io/badge/Product%20Hunt-%231%20Product%20of%20the%20Day-%23DA552E" alt="Product Hunt"></a>
|
||||
<a href="https://discord.gg/xpCwq3Kfn8">
|
||||
<img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Discord Chat" />
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=medusajs">
|
||||
<img src="https://img.shields.io/twitter/follow/medusajs.svg?label=Follow%20@medusajs" alt="Follow @medusajs" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Overview
|
||||
|
||||
Local Event Bus module for Medusa. When installed, the events system of Medusa is powered by the Node EventEmitter. This module installed by default in new (> v1.8.0) Medusa projects.
|
||||
|
||||
The Node EventEmitter is limited to a single process environment. We generally recommend using the `@medusajs/event-bus-redis` module in a production environment.
|
||||
|
||||
## Getting started
|
||||
|
||||
Install the module:
|
||||
|
||||
```bash
|
||||
yarn add @medusajs/event-bus-local
|
||||
```
|
||||
|
||||
You don't need to add the module to your project configuration as it is the default one. Medusa will try to use it, if no other event buses are installed.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// ...
|
||||
modules: [ ... ],
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The module comes with no configuration options.
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
globals: {
|
||||
"ts-jest": {
|
||||
tsConfig: "tsconfig.spec.json",
|
||||
isolatedModules: false,
|
||||
},
|
||||
},
|
||||
transform: {
|
||||
"^.+\\.[jt]s?$": "ts-jest",
|
||||
},
|
||||
testEnvironment: `node`,
|
||||
moduleFileExtensions: [`js`, `jsx`, `ts`, `tsx`, `json`],
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@medusajs/event-bus-local",
|
||||
"version": "0.1.0",
|
||||
"description": "Local Event Bus Module for Medusa",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa",
|
||||
"directory": "packages/event-bus-local"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"author": "Medusa",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@medusajs/types": "^0.0.1",
|
||||
"cross-env": "^5.2.1",
|
||||
"jest": "^25.5.2",
|
||||
"ts-jest": "^25.5.1",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "tsc --build --watch",
|
||||
"prepare": "cross-env NODE_ENV=production yarn run build",
|
||||
"build": "tsc --build",
|
||||
"test": "jest --passWithNoTests",
|
||||
"test:unit": "jest --passWithNoTests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@medusajs/modules-sdk": "*",
|
||||
"@medusajs/utils": "^0.0.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ModuleExports } from "@medusajs/modules-sdk"
|
||||
import Loader from "./loaders"
|
||||
import LocalEventBus from "./services/event-bus-local"
|
||||
|
||||
export const service = LocalEventBus
|
||||
export const loaders = [Loader]
|
||||
|
||||
const moduleDefinition: ModuleExports = {
|
||||
service,
|
||||
loaders,
|
||||
}
|
||||
|
||||
export default moduleDefinition
|
||||
@@ -0,0 +1,8 @@
|
||||
import { LoaderOptions } from "@medusajs/modules-sdk"
|
||||
|
||||
|
||||
export default async ({ logger }: LoaderOptions): Promise<void> => {
|
||||
logger?.warn(
|
||||
"Local Event Bus installed. This is not recommended for production."
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import LocalEventBusService from "../event-bus-local"
|
||||
|
||||
jest.genMockFromModule("events")
|
||||
jest.mock("events")
|
||||
|
||||
const loggerMock = {
|
||||
info: jest.fn().mockReturnValue(console.log),
|
||||
warn: jest.fn().mockReturnValue(console.log),
|
||||
error: jest.fn().mockReturnValue(console.log),
|
||||
}
|
||||
|
||||
const moduleDeps = {
|
||||
logger: loggerMock,
|
||||
}
|
||||
|
||||
describe("LocalEventBusService", () => {
|
||||
let eventBus
|
||||
|
||||
describe("emit", () => {
|
||||
describe("Successfully emits events", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("Emits an event", () => {
|
||||
eventBus = new LocalEventBusService(
|
||||
moduleDeps,
|
||||
{},
|
||||
{
|
||||
resources: "shared",
|
||||
}
|
||||
)
|
||||
|
||||
eventBus.eventEmitter_.emit.mockImplementationOnce((data) => data)
|
||||
|
||||
eventBus.emit("eventName", { hi: "1234" })
|
||||
|
||||
expect(eventBus.eventEmitter_.emit).toHaveBeenCalledTimes(1)
|
||||
expect(eventBus.eventEmitter_.emit).toHaveBeenCalledWith("eventName", {
|
||||
hi: "1234",
|
||||
})
|
||||
})
|
||||
|
||||
it("Emits multiple events", () => {
|
||||
eventBus = new LocalEventBusService(
|
||||
moduleDeps,
|
||||
{},
|
||||
{
|
||||
resources: "shared",
|
||||
}
|
||||
)
|
||||
|
||||
eventBus.eventEmitter_.emit.mockImplementationOnce((data) => data)
|
||||
|
||||
eventBus.emit([
|
||||
{ eventName: "event-1", data: { hi: "1234" } },
|
||||
{ eventName: "event-2", data: { hi: "5678" } },
|
||||
])
|
||||
|
||||
expect(eventBus.eventEmitter_.emit).toHaveBeenCalledTimes(2)
|
||||
expect(eventBus.eventEmitter_.emit).toHaveBeenCalledWith("event-1", {
|
||||
hi: "1234",
|
||||
})
|
||||
expect(eventBus.eventEmitter_.emit).toHaveBeenCalledWith("event-2", {
|
||||
hi: "5678",
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,80 @@
|
||||
import { Logger, MedusaContainer } from "@medusajs/modules-sdk"
|
||||
import { EmitData, Subscriber } from "@medusajs/types"
|
||||
import { AbstractEventBusModuleService } from "@medusajs/utils"
|
||||
import { EventEmitter } from "events"
|
||||
|
||||
type InjectedDependencies = {
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
const eventEmitter = new EventEmitter()
|
||||
|
||||
export default class LocalEventBusService extends AbstractEventBusModuleService {
|
||||
protected readonly logger_: Logger
|
||||
protected readonly eventEmitter_: EventEmitter
|
||||
|
||||
constructor({ logger }: MedusaContainer & InjectedDependencies) {
|
||||
// @ts-ignore
|
||||
super(...arguments)
|
||||
|
||||
this.logger_ = logger
|
||||
this.eventEmitter_ = eventEmitter
|
||||
}
|
||||
|
||||
async emit<T>(
|
||||
eventName: string,
|
||||
data: T,
|
||||
options: Record<string, unknown>
|
||||
): Promise<void>
|
||||
|
||||
/**
|
||||
* Emit a number of events
|
||||
* @param {EmitData} data - the data to send to the subscriber.
|
||||
*/
|
||||
async emit<T>(data: EmitData<T>[]): Promise<void>
|
||||
|
||||
async emit<T, TInput extends string | EmitData<T>[] = string>(
|
||||
eventOrData: TInput,
|
||||
data?: T,
|
||||
options: Record<string, unknown> = {}
|
||||
): Promise<void> {
|
||||
const isBulkEmit = Array.isArray(eventOrData)
|
||||
|
||||
const events: EmitData[] = isBulkEmit
|
||||
? eventOrData
|
||||
: [{ eventName: eventOrData, data }]
|
||||
|
||||
for (const event of events) {
|
||||
const eventListenersCount = this.eventEmitter_.listenerCount(
|
||||
event.eventName
|
||||
)
|
||||
|
||||
this.logger_.info(
|
||||
`Processing ${event.eventName} which has ${eventListenersCount} subscribers`
|
||||
)
|
||||
|
||||
if (eventListenersCount === 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
this.eventEmitter_.emit(event.eventName, event.data)
|
||||
} catch (error) {
|
||||
this.logger_.error(
|
||||
`An error occurred while processing ${event.eventName}: ${error}`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subscribe(event: string | symbol, subscriber: Subscriber): this {
|
||||
this.eventEmitter_.on(event, subscriber)
|
||||
return this
|
||||
}
|
||||
|
||||
unsubscribe(event: string | symbol, subscriber: Subscriber): this {
|
||||
this.eventEmitter_.off(event, subscriber)
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["es5", "es6", "es2019"],
|
||||
"target": "es6",
|
||||
"outDir": "./dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"downlevelIteration": true // to use ES5 specific tooling
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"./src/**/__tests__",
|
||||
"./src/**/__mocks__",
|
||||
"./src/**/__fixtures__",
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in new issue
Block a user