chore: workflow internals improvementss (#9455)
This commit is contained in:
@@ -1170,6 +1170,7 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
await deleteLineItemsWorkflow(appContainer).run({
|
await deleteLineItemsWorkflow(appContainer).run({
|
||||||
input: {
|
input: {
|
||||||
|
cart_id: cart.id,
|
||||||
ids: items.map((i) => i.id),
|
ids: items.map((i) => i.id),
|
||||||
},
|
},
|
||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
@@ -1211,6 +1212,7 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
const { errors } = await workflow.run({
|
const { errors } = await workflow.run({
|
||||||
input: {
|
input: {
|
||||||
|
cart_id: cart.id,
|
||||||
ids: items.map((i) => i.id),
|
ids: items.map((i) => i.id),
|
||||||
},
|
},
|
||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
ProductStatus,
|
ProductStatus,
|
||||||
PromotionRuleOperator,
|
PromotionRuleOperator,
|
||||||
PromotionType,
|
PromotionType,
|
||||||
RuleOperator
|
RuleOperator,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
import {
|
import {
|
||||||
@@ -2131,6 +2131,7 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
expect(response.data.cart).toEqual(
|
expect(response.data.cart).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: cart.id,
|
id: cart.id,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { MedusaError } from "@medusajs/framework/utils"
|
import { MedusaError } from "@medusajs/framework/utils"
|
||||||
import {
|
import {
|
||||||
WorkflowData,
|
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
|
parallelize,
|
||||||
transform,
|
transform,
|
||||||
|
WorkflowData,
|
||||||
} from "@medusajs/framework/workflows-sdk"
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
|
import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
|
||||||
import {
|
import {
|
||||||
@@ -102,13 +103,14 @@ export const addShippingMethodToWorkflow = createWorkflow(
|
|||||||
return cart.shipping_methods.map((sm) => sm.id)
|
return cart.shipping_methods.map((sm) => sm.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
removeShippingMethodFromCartStep({
|
const [, shippingMethodsToAdd] = parallelize(
|
||||||
shipping_method_ids: currentShippingMethods,
|
removeShippingMethodFromCartStep({
|
||||||
})
|
shipping_method_ids: currentShippingMethods,
|
||||||
|
}),
|
||||||
const shippingMethodsToAdd = addShippingMethodToCartStep({
|
addShippingMethodToCartStep({
|
||||||
shipping_methods: shippingMethodInput,
|
shipping_methods: shippingMethodInput,
|
||||||
})
|
})
|
||||||
|
)
|
||||||
|
|
||||||
updateTaxLinesWorkflow.runAsStep({
|
updateTaxLinesWorkflow.runAsStep({
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ export const completeCartWorkflow = createWorkflow(
|
|||||||
name: completeCartWorkflowId,
|
name: completeCartWorkflowId,
|
||||||
store: true,
|
store: true,
|
||||||
idempotent: true,
|
idempotent: true,
|
||||||
// 3 days of retention time
|
|
||||||
retentionTime: THREE_DAYS,
|
retentionTime: THREE_DAYS,
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -117,7 +117,10 @@ export const createCartWorkflow = createWorkflow(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there is only one country in the region, we prepare a shipping address with that country's code.
|
// If there is only one country in the region, we prepare a shipping address with that country's code.
|
||||||
if (!data.input.shipping_address && data.region.countries.length === 1) {
|
if (
|
||||||
|
!data.input.shipping_address &&
|
||||||
|
data.region.countries.length === 1
|
||||||
|
) {
|
||||||
data_.shipping_address = {
|
data_.shipping_address = {
|
||||||
country_code: data.region.countries[0].iso_2,
|
country_code: data.region.countries[0].iso_2,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import {
|
|||||||
} from "@medusajs/framework/types"
|
} from "@medusajs/framework/types"
|
||||||
import { Modules } from "@medusajs/framework/utils"
|
import { Modules } from "@medusajs/framework/utils"
|
||||||
import {
|
import {
|
||||||
WorkflowData,
|
|
||||||
createStep,
|
createStep,
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
|
parallelize,
|
||||||
transform,
|
transform,
|
||||||
|
WorkflowData,
|
||||||
} from "@medusajs/framework/workflows-sdk"
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
import { createRemoteLinkStep } from "../../common/steps/create-remote-links"
|
import { createRemoteLinkStep } from "../../common/steps/create-remote-links"
|
||||||
import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
|
import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
|
||||||
@@ -52,9 +53,10 @@ export const createPaymentCollectionForCartWorkflow = createWorkflow(
|
|||||||
list: false,
|
list: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
validateCartStep({ cart })
|
parallelize(
|
||||||
|
validateCartStep({ cart }),
|
||||||
validateExistingPaymentCollectionStep({ cart })
|
validateExistingPaymentCollectionStep({ cart })
|
||||||
|
)
|
||||||
|
|
||||||
const paymentData = transform({ cart }, ({ cart }) => {
|
const paymentData = transform({ cart }, ({ cart }) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import {
|
|||||||
} from "@medusajs/framework/types"
|
} from "@medusajs/framework/types"
|
||||||
import { MedusaError, PromotionActions } from "@medusajs/framework/utils"
|
import { MedusaError, PromotionActions } from "@medusajs/framework/utils"
|
||||||
import {
|
import {
|
||||||
WorkflowData,
|
|
||||||
WorkflowResponse,
|
|
||||||
createHook,
|
createHook,
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
parallelize,
|
parallelize,
|
||||||
transform,
|
transform,
|
||||||
when,
|
when,
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
} from "@medusajs/framework/workflows-sdk"
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
import { useRemoteQueryStep } from "../../common"
|
import { useRemoteQueryStep } from "../../common"
|
||||||
import {
|
import {
|
||||||
@@ -138,14 +138,13 @@ export const updateCartWorkflow = createWorkflow(
|
|||||||
list: false,
|
list: false,
|
||||||
}).config({ name: "refetch–cart" })
|
}).config({ name: "refetch–cart" })
|
||||||
|
|
||||||
parallelize(
|
refreshCartShippingMethodsStep({ cart })
|
||||||
refreshCartShippingMethodsStep({ cart }),
|
|
||||||
updateTaxLinesWorkflow.runAsStep({
|
updateTaxLinesWorkflow.runAsStep({
|
||||||
input: {
|
input: {
|
||||||
cart_id: carts[0].id,
|
cart_id: carts[0].id,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
|
||||||
|
|
||||||
updateCartPromotionsWorkflow.runAsStep({
|
updateCartPromotionsWorkflow.runAsStep({
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
@@ -3,8 +3,12 @@ import {
|
|||||||
Logger,
|
Logger,
|
||||||
PaymentSessionDTO,
|
PaymentSessionDTO,
|
||||||
} from "@medusajs/framework/types"
|
} from "@medusajs/framework/types"
|
||||||
import { ContainerRegistrationKeys, Modules } from "@medusajs/framework/utils"
|
import {
|
||||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
ContainerRegistrationKeys,
|
||||||
|
Modules,
|
||||||
|
promiseAll,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||||
|
|
||||||
export interface DeletePaymentSessionStepInput {
|
export interface DeletePaymentSessionStepInput {
|
||||||
ids: string[]
|
ids: string[]
|
||||||
@@ -29,32 +33,42 @@ export const deletePaymentSessionsStep = createStep(
|
|||||||
return new StepResponse([], null)
|
return new StepResponse([], null)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const id of ids) {
|
const select = [
|
||||||
const select = [
|
"provider_id",
|
||||||
"provider_id",
|
"currency_code",
|
||||||
"currency_code",
|
"amount",
|
||||||
"amount",
|
"data",
|
||||||
"data",
|
"context",
|
||||||
"context",
|
"payment_collection.id",
|
||||||
"payment_collection.id",
|
]
|
||||||
]
|
|
||||||
|
|
||||||
const [session] = await service.listPaymentSessions({ id }, { select })
|
const sessions = await service.listPaymentSessions({ id: ids }, { select })
|
||||||
|
const sessionMap = new Map(sessions.map((s) => [s.id, s]))
|
||||||
|
|
||||||
|
const promises: Promise<void>[] = []
|
||||||
|
|
||||||
|
for (const id of ids) {
|
||||||
|
const session = sessionMap.get(id)!
|
||||||
|
|
||||||
// As this requires an external method call, we will try to delete as many successful calls
|
// As this requires an external method call, we will try to delete as many successful calls
|
||||||
// as possible and pass them over to the compensation step to be recreated if any of the
|
// as possible and pass them over to the compensation step to be recreated if any of the
|
||||||
// payment sessions fails to delete.
|
// payment sessions fails to delete.
|
||||||
try {
|
const promise = service
|
||||||
await service.deletePaymentSession(id)
|
.deletePaymentSession(id)
|
||||||
|
.then((res) => {
|
||||||
|
deleted.push(session)
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
logger.error(
|
||||||
|
`Encountered an error when trying to delete payment session - ${id} - ${e}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
deleted.push(session)
|
promises.push(promise)
|
||||||
} catch (e) {
|
|
||||||
logger.error(
|
|
||||||
`Encountered an error when trying to delete payment session - ${id} - ${e}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await promiseAll(promises)
|
||||||
|
|
||||||
return new StepResponse(
|
return new StepResponse(
|
||||||
deleted.map((d) => d.id),
|
deleted.map((d) => d.id),
|
||||||
deleted
|
deleted
|
||||||
|
|||||||
@@ -83,6 +83,14 @@ class DistributedTransaction extends EventEmitter {
|
|||||||
private readonly context: TransactionContext = new TransactionContext()
|
private readonly context: TransactionContext = new TransactionContext()
|
||||||
private static keyValueStore: IDistributedTransactionStorage
|
private static keyValueStore: IDistributedTransactionStorage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store data during the life cycle of the current transaction execution.
|
||||||
|
* Store non persistent data such as transformers results, temporary data, etc.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#temporaryStorage = new Map<string, unknown>()
|
||||||
|
|
||||||
public static setStorage(storage: IDistributedTransactionStorage) {
|
public static setStorage(storage: IDistributedTransactionStorage) {
|
||||||
this.keyValueStore = storage
|
this.keyValueStore = storage
|
||||||
}
|
}
|
||||||
@@ -298,6 +306,18 @@ class DistributedTransaction extends EventEmitter {
|
|||||||
|
|
||||||
await DistributedTransaction.keyValueStore.clearStepTimeout(this, step)
|
await DistributedTransaction.keyValueStore.clearStepTimeout(this, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setTemporaryData(key: string, value: unknown) {
|
||||||
|
this.#temporaryStorage.set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTemporaryData(key: string) {
|
||||||
|
return this.#temporaryStorage.get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasTemporaryData(key: string) {
|
||||||
|
return this.#temporaryStorage.has(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributedTransaction.setStorage(
|
DistributedTransaction.setStorage(
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Context, LoadedModule, MedusaContainer } from "@medusajs/types"
|
import { Context, LoadedModule, MedusaContainer } from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
|
createMedusaContainer,
|
||||||
|
isDefined,
|
||||||
|
isString,
|
||||||
MedusaContext,
|
MedusaContext,
|
||||||
MedusaContextType,
|
MedusaContextType,
|
||||||
MedusaError,
|
MedusaError,
|
||||||
MedusaModuleType,
|
MedusaModuleType,
|
||||||
createMedusaContainer,
|
|
||||||
isDefined,
|
|
||||||
isString,
|
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { asValue } from "awilix"
|
import { asValue } from "awilix"
|
||||||
import {
|
import {
|
||||||
@@ -107,9 +107,17 @@ export class LocalWorkflow {
|
|||||||
return resolved
|
return resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wrappableMethods = Object.getOwnPropertyNames(resolved).filter(
|
||||||
|
(key) => key !== "constructor"
|
||||||
|
)
|
||||||
|
|
||||||
return new Proxy(resolved, {
|
return new Proxy(resolved, {
|
||||||
get: function (target, prop) {
|
get: function (target, prop) {
|
||||||
if (typeof target[prop] !== "function") {
|
const shouldWrap =
|
||||||
|
wrappableMethods.includes(prop as string) &&
|
||||||
|
typeof target[prop] === "function"
|
||||||
|
|
||||||
|
if (!shouldWrap) {
|
||||||
return target[prop]
|
return target[prop]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +139,7 @@ export class LocalWorkflow {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,9 +378,11 @@ export class LocalWorkflow {
|
|||||||
|
|
||||||
await orchestrator.resume(transaction)
|
await orchestrator.resume(transaction)
|
||||||
|
|
||||||
cleanUpEventListeners()
|
try {
|
||||||
|
return transaction
|
||||||
return transaction
|
} finally {
|
||||||
|
cleanUpEventListeners()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRunningTransaction(uniqueTransactionId: string, context?: Context) {
|
async getRunningTransaction(uniqueTransactionId: string, context?: Context) {
|
||||||
@@ -406,9 +417,11 @@ export class LocalWorkflow {
|
|||||||
|
|
||||||
await orchestrator.cancelTransaction(transaction)
|
await orchestrator.cancelTransaction(transaction)
|
||||||
|
|
||||||
cleanUpEventListeners()
|
try {
|
||||||
|
return transaction
|
||||||
return transaction
|
} finally {
|
||||||
|
cleanUpEventListeners()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerStepSuccess(
|
async registerStepSuccess(
|
||||||
@@ -433,9 +446,11 @@ export class LocalWorkflow {
|
|||||||
response
|
response
|
||||||
)
|
)
|
||||||
|
|
||||||
cleanUpEventListeners()
|
try {
|
||||||
|
return transaction
|
||||||
return transaction
|
} finally {
|
||||||
|
cleanUpEventListeners()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerStepFailure(
|
async registerStepFailure(
|
||||||
@@ -459,9 +474,11 @@ export class LocalWorkflow {
|
|||||||
handler(this.container_, context)
|
handler(this.container_, context)
|
||||||
)
|
)
|
||||||
|
|
||||||
cleanUpEventListeners()
|
try {
|
||||||
|
return transaction
|
||||||
return transaction
|
} finally {
|
||||||
|
cleanUpEventListeners()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setOptions(options: Partial<TransactionModelOptions>) {
|
setOptions(options: Partial<TransactionModelOptions>) {
|
||||||
|
|||||||
@@ -1,36 +1,56 @@
|
|||||||
import { isObject } from "./is-object"
|
import { isObject } from "./is-object"
|
||||||
|
import * as util from "node:util"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In most casees, JSON.parse(JSON.stringify(obj)) is enough to deep copy an object.
|
* In most casees, JSON.parse(JSON.stringify(obj)) is enough to deep copy an object.
|
||||||
* But in some cases, it's not enough. For example, if the object contains a function or a proxy, it will be lost after JSON.parse(JSON.stringify(obj)).
|
* But in some cases, it's not enough. For example, if the object contains a function or a proxy, it will be lost after JSON.parse(JSON.stringify(obj)).
|
||||||
*
|
*
|
||||||
* @param obj
|
* @param obj
|
||||||
|
* @param cache
|
||||||
*/
|
*/
|
||||||
export function deepCopy<
|
export function deepCopy<
|
||||||
T extends Record<any, any> | Record<any, any>[] = Record<any, any>,
|
T extends Record<any, any> | Record<any, any>[] = Record<any, any>,
|
||||||
TOutput = T extends [] ? T[] : T
|
TOutput = T extends [] ? T[] : T
|
||||||
>(obj: T): TOutput {
|
>(obj: T, cache = new WeakMap()): TOutput {
|
||||||
if (obj === null || typeof obj !== "object") {
|
if (obj === null || typeof obj !== "object") {
|
||||||
return obj
|
return obj as TOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle circular references with cache
|
||||||
|
if (cache.has(obj)) {
|
||||||
|
return cache.get(obj) as TOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
let copy: TOutput
|
||||||
|
|
||||||
|
// Handle arrays
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
const copy: any[] = []
|
copy = [] as unknown as TOutput
|
||||||
for (let i = 0; i < obj.length; i++) {
|
cache.set(obj, copy) // Add to cache before recursing
|
||||||
copy[i] = deepCopy(obj[i])
|
;(obj as Array<any>).forEach((item, index) => {
|
||||||
}
|
;(copy as Array<any>)[index] = deepCopy(item, cache)
|
||||||
return copy as TOutput
|
})
|
||||||
}
|
|
||||||
|
|
||||||
if (isObject(obj)) {
|
|
||||||
const copy: Record<any, any> = {}
|
|
||||||
for (let attr in obj) {
|
|
||||||
if (obj.hasOwnProperty(attr)) {
|
|
||||||
copy[attr] = deepCopy(obj[attr] as T)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return copy
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj
|
// Handle objects
|
||||||
|
if (isObject(obj)) {
|
||||||
|
if (util.types.isProxy(obj)) {
|
||||||
|
return obj as unknown as TOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
copy = {} as TOutput
|
||||||
|
cache.set(obj, copy) // Add to cache before recursing
|
||||||
|
|
||||||
|
Object.keys(obj).forEach((key) => {
|
||||||
|
;(copy as Record<any, any>)[key] = deepCopy(
|
||||||
|
(obj as Record<any, any>)[key],
|
||||||
|
cache
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj as TOutput
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
import { EventBusTypes } from "@medusajs/types"
|
import {
|
||||||
|
EventBusTypes,
|
||||||
|
InternalModuleDeclaration,
|
||||||
|
MedusaContainer,
|
||||||
|
} from "@medusajs/types"
|
||||||
import { ulid } from "ulid"
|
import { ulid } from "ulid"
|
||||||
|
|
||||||
export abstract class AbstractEventBusModuleService
|
export abstract class AbstractEventBusModuleService
|
||||||
implements EventBusTypes.IEventBusModuleService
|
implements EventBusTypes.IEventBusModuleService
|
||||||
{
|
{
|
||||||
|
protected isWorkerMode: boolean = true
|
||||||
|
|
||||||
protected eventToSubscribersMap_: Map<
|
protected eventToSubscribersMap_: Map<
|
||||||
string | symbol,
|
string | symbol,
|
||||||
EventBusTypes.SubscriberDescriptor[]
|
EventBusTypes.SubscriberDescriptor[]
|
||||||
@@ -16,6 +22,14 @@ export abstract class AbstractEventBusModuleService
|
|||||||
return this.eventToSubscribersMap_
|
return this.eventToSubscribersMap_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected constructor(
|
||||||
|
container: MedusaContainer,
|
||||||
|
moduleOptions = {},
|
||||||
|
moduleDeclaration: InternalModuleDeclaration
|
||||||
|
) {
|
||||||
|
this.isWorkerMode = moduleDeclaration.worker_mode !== "server"
|
||||||
|
}
|
||||||
|
|
||||||
abstract emit<T>(
|
abstract emit<T>(
|
||||||
data: EventBusTypes.Message<T> | EventBusTypes.Message<T>[],
|
data: EventBusTypes.Message<T> | EventBusTypes.Message<T>[],
|
||||||
options: Record<string, unknown>
|
options: Record<string, unknown>
|
||||||
@@ -63,6 +77,10 @@ export abstract class AbstractEventBusModuleService
|
|||||||
subscriber: EventBusTypes.Subscriber,
|
subscriber: EventBusTypes.Subscriber,
|
||||||
context?: EventBusTypes.SubscriberContext
|
context?: EventBusTypes.SubscriberContext
|
||||||
): this {
|
): this {
|
||||||
|
if (!this.isWorkerMode) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof subscriber !== `function`) {
|
if (typeof subscriber !== `function`) {
|
||||||
throw new Error("Subscriber must be a function")
|
throw new Error("Subscriber must be a function")
|
||||||
}
|
}
|
||||||
@@ -88,6 +106,10 @@ export abstract class AbstractEventBusModuleService
|
|||||||
subscriber: EventBusTypes.Subscriber,
|
subscriber: EventBusTypes.Subscriber,
|
||||||
context: EventBusTypes.SubscriberContext
|
context: EventBusTypes.SubscriberContext
|
||||||
): this {
|
): this {
|
||||||
|
if (!this.isWorkerMode) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof subscriber !== `function`) {
|
if (typeof subscriber !== `function`) {
|
||||||
throw new Error("Subscriber must be a function")
|
throw new Error("Subscriber must be a function")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ function createContextualWorkflowRunner<
|
|||||||
events,
|
events,
|
||||||
flowMetadata,
|
flowMetadata,
|
||||||
]
|
]
|
||||||
const transaction = await method.apply(method, args)
|
const transaction = await method.apply(method, args) as DistributedTransactionType
|
||||||
|
|
||||||
let errors = transaction.getErrors(TransactionHandlerType.INVOKE)
|
let errors = transaction.getErrors(TransactionHandlerType.INVOKE)
|
||||||
|
|
||||||
|
|||||||
@@ -150,55 +150,67 @@ export function applyStep<
|
|||||||
const ret = {
|
const ret = {
|
||||||
__type: OrchestrationUtils.SymbolWorkflowStep,
|
__type: OrchestrationUtils.SymbolWorkflowStep,
|
||||||
__step__: stepName,
|
__step__: stepName,
|
||||||
config: (localConfig: LocalStepConfig) => {
|
}
|
||||||
const newStepName = localConfig.name ?? stepName
|
|
||||||
const newConfig = {
|
|
||||||
...stepConfig,
|
|
||||||
...localConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
delete localConfig.name
|
const refRet = proxify(ret) as WorkflowData<TInvokeResultOutput> & {
|
||||||
|
|
||||||
this.handlers.set(newStepName, handler)
|
|
||||||
|
|
||||||
this.flow.replaceAction(stepConfig.uuid!, newStepName, newConfig)
|
|
||||||
this.isAsync ||= !!(newConfig.async || newConfig.compensateAsync)
|
|
||||||
|
|
||||||
ret.__step__ = newStepName
|
|
||||||
WorkflowManager.update(this.workflowId, this.flow, this.handlers)
|
|
||||||
|
|
||||||
const confRef = proxify(ret)
|
|
||||||
|
|
||||||
if (global[OrchestrationUtils.SymbolMedusaWorkflowComposerCondition]) {
|
|
||||||
const flagSteps =
|
|
||||||
global[OrchestrationUtils.SymbolMedusaWorkflowComposerCondition]
|
|
||||||
.steps
|
|
||||||
|
|
||||||
const idx = flagSteps.findIndex((a) => a.__step__ === ret.__step__)
|
|
||||||
if (idx > -1) {
|
|
||||||
flagSteps.splice(idx, 1)
|
|
||||||
}
|
|
||||||
flagSteps.push(confRef)
|
|
||||||
}
|
|
||||||
|
|
||||||
return confRef as StepFunction<TInvokeInput, TInvokeResultOutput>
|
|
||||||
},
|
|
||||||
if: (
|
if: (
|
||||||
input: any,
|
input: any,
|
||||||
condition: (...args: any) => boolean | WorkflowData
|
condition: (...args: any) => boolean | WorkflowData
|
||||||
): WorkflowData<TInvokeResultOutput> => {
|
) => WorkflowData<TInvokeResultOutput>
|
||||||
if (typeof condition !== "function") {
|
|
||||||
throw new Error("Condition must be a function")
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapConditionalStep(input, condition, handler)
|
|
||||||
this.handlers.set(ret.__step__, handler)
|
|
||||||
|
|
||||||
return proxify(ret)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const refRet = proxify(ret) as WorkflowData<TInvokeResultOutput>
|
refRet.config = (
|
||||||
|
localConfig: { name?: string } & Omit<
|
||||||
|
TransactionStepsDefinition,
|
||||||
|
"next" | "uuid" | "action"
|
||||||
|
>
|
||||||
|
) => {
|
||||||
|
const newStepName = localConfig.name ?? stepName
|
||||||
|
const newConfig = {
|
||||||
|
async: false,
|
||||||
|
compensateAsync: false,
|
||||||
|
...stepConfig,
|
||||||
|
...localConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
delete localConfig.name
|
||||||
|
|
||||||
|
this.handlers.set(newStepName, handler)
|
||||||
|
|
||||||
|
this.flow.replaceAction(stepConfig.uuid!, newStepName, newConfig)
|
||||||
|
this.isAsync ||= !!(newConfig.async || newConfig.compensateAsync)
|
||||||
|
|
||||||
|
ret.__step__ = newStepName
|
||||||
|
WorkflowManager.update(this.workflowId, this.flow, this.handlers)
|
||||||
|
|
||||||
|
//const confRef = proxify(ret)
|
||||||
|
|
||||||
|
if (global[OrchestrationUtils.SymbolMedusaWorkflowComposerCondition]) {
|
||||||
|
const flagSteps =
|
||||||
|
global[OrchestrationUtils.SymbolMedusaWorkflowComposerCondition].steps
|
||||||
|
|
||||||
|
const idx = flagSteps.findIndex((a) => a.__step__ === ret.__step__)
|
||||||
|
if (idx > -1) {
|
||||||
|
flagSteps.splice(idx, 1)
|
||||||
|
}
|
||||||
|
flagSteps.push(refRet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return refRet
|
||||||
|
}
|
||||||
|
refRet.if = (
|
||||||
|
input: any,
|
||||||
|
condition: (...args: any) => boolean | WorkflowData
|
||||||
|
): WorkflowData<TInvokeResultOutput> => {
|
||||||
|
if (typeof condition !== "function") {
|
||||||
|
throw new Error("Condition must be a function")
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapConditionalStep(input, condition, handler)
|
||||||
|
this.handlers.set(ret.__step__, handler)
|
||||||
|
|
||||||
|
return refRet
|
||||||
|
}
|
||||||
|
|
||||||
if (global[OrchestrationUtils.SymbolMedusaWorkflowComposerCondition]) {
|
if (global[OrchestrationUtils.SymbolMedusaWorkflowComposerCondition]) {
|
||||||
global[
|
global[
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { WorkflowStepHandlerArguments } from "@medusajs/orchestration"
|
import { WorkflowStepHandlerArguments } from "@medusajs/orchestration"
|
||||||
import { OrchestrationUtils, deepCopy } from "@medusajs/utils"
|
import { OrchestrationUtils } from "@medusajs/utils"
|
||||||
import { ApplyStepOptions } from "../create-step"
|
import { ApplyStepOptions } from "../create-step"
|
||||||
import {
|
import {
|
||||||
CreateWorkflowComposerContext,
|
CreateWorkflowComposerContext,
|
||||||
@@ -9,6 +9,37 @@ import {
|
|||||||
import { resolveValue } from "./resolve-value"
|
import { resolveValue } from "./resolve-value"
|
||||||
import { StepResponse } from "./step-response"
|
import { StepResponse } from "./step-response"
|
||||||
|
|
||||||
|
function buildStepContext({
|
||||||
|
action,
|
||||||
|
stepArguments,
|
||||||
|
}: {
|
||||||
|
action: StepExecutionContext["action"]
|
||||||
|
stepArguments: WorkflowStepHandlerArguments
|
||||||
|
}) {
|
||||||
|
const metadata = stepArguments.metadata
|
||||||
|
const idempotencyKey = metadata.idempotency_key
|
||||||
|
|
||||||
|
stepArguments.context!.idempotencyKey = idempotencyKey
|
||||||
|
|
||||||
|
const flowMetadata = stepArguments.transaction.getFlow()?.metadata
|
||||||
|
const executionContext: StepExecutionContext = {
|
||||||
|
workflowId: metadata.model_id,
|
||||||
|
stepName: metadata.action,
|
||||||
|
action,
|
||||||
|
idempotencyKey,
|
||||||
|
attempt: metadata.attempt,
|
||||||
|
container: stepArguments.container,
|
||||||
|
metadata,
|
||||||
|
eventGroupId:
|
||||||
|
flowMetadata?.eventGroupId ?? stepArguments.context!.eventGroupId,
|
||||||
|
parentStepIdempotencyKey: flowMetadata?.parentStepIdempotencyKey as string,
|
||||||
|
transactionId: stepArguments.context!.transactionId,
|
||||||
|
context: stepArguments.context!,
|
||||||
|
}
|
||||||
|
|
||||||
|
return executionContext
|
||||||
|
}
|
||||||
|
|
||||||
export function createStepHandler<
|
export function createStepHandler<
|
||||||
TInvokeInput,
|
TInvokeInput,
|
||||||
TStepInput extends {
|
TStepInput extends {
|
||||||
@@ -32,27 +63,10 @@ export function createStepHandler<
|
|||||||
) {
|
) {
|
||||||
const handler = {
|
const handler = {
|
||||||
invoke: async (stepArguments: WorkflowStepHandlerArguments) => {
|
invoke: async (stepArguments: WorkflowStepHandlerArguments) => {
|
||||||
const metadata = stepArguments.metadata
|
const executionContext = buildStepContext({
|
||||||
const idempotencyKey = metadata.idempotency_key
|
|
||||||
|
|
||||||
stepArguments.context!.idempotencyKey = idempotencyKey
|
|
||||||
|
|
||||||
const flowMetadata = stepArguments.transaction.getFlow()?.metadata
|
|
||||||
const executionContext: StepExecutionContext = {
|
|
||||||
workflowId: metadata.model_id,
|
|
||||||
stepName: metadata.action,
|
|
||||||
action: "invoke",
|
action: "invoke",
|
||||||
idempotencyKey,
|
stepArguments,
|
||||||
attempt: metadata.attempt,
|
})
|
||||||
container: stepArguments.container,
|
|
||||||
metadata,
|
|
||||||
eventGroupId:
|
|
||||||
flowMetadata?.eventGroupId ?? stepArguments.context!.eventGroupId,
|
|
||||||
parentStepIdempotencyKey:
|
|
||||||
flowMetadata?.parentStepIdempotencyKey as string,
|
|
||||||
transactionId: stepArguments.context!.transactionId,
|
|
||||||
context: stepArguments.context!,
|
|
||||||
}
|
|
||||||
|
|
||||||
const argInput = input ? await resolveValue(input, stepArguments) : {}
|
const argInput = input ? await resolveValue(input, stepArguments) : {}
|
||||||
const stepResponse: StepResponse<any, any> = await invokeFn.apply(this, [
|
const stepResponse: StepResponse<any, any> = await invokeFn.apply(this, [
|
||||||
@@ -72,31 +86,16 @@ export function createStepHandler<
|
|||||||
},
|
},
|
||||||
compensate: compensateFn
|
compensate: compensateFn
|
||||||
? async (stepArguments: WorkflowStepHandlerArguments) => {
|
? async (stepArguments: WorkflowStepHandlerArguments) => {
|
||||||
const metadata = stepArguments.metadata
|
const executionContext = buildStepContext({
|
||||||
const idempotencyKey = metadata.idempotency_key
|
|
||||||
|
|
||||||
stepArguments.context!.idempotencyKey = idempotencyKey
|
|
||||||
|
|
||||||
const flowMetadata = stepArguments.transaction.getFlow()?.metadata
|
|
||||||
const executionContext: StepExecutionContext = {
|
|
||||||
workflowId: metadata.model_id,
|
|
||||||
stepName: metadata.action,
|
|
||||||
action: "compensate",
|
action: "compensate",
|
||||||
idempotencyKey,
|
stepArguments,
|
||||||
parentStepIdempotencyKey:
|
})
|
||||||
flowMetadata?.parentStepIdempotencyKey as string,
|
|
||||||
attempt: metadata.attempt,
|
|
||||||
container: stepArguments.container,
|
|
||||||
metadata,
|
|
||||||
context: stepArguments.context!,
|
|
||||||
}
|
|
||||||
|
|
||||||
const stepOutput = (stepArguments.invoke[stepName] as any)?.output
|
const stepOutput = (stepArguments.invoke[stepName] as any)?.output
|
||||||
const invokeResult =
|
const invokeResult =
|
||||||
stepOutput?.__type === OrchestrationUtils.SymbolWorkflowStepResponse
|
stepOutput?.__type === OrchestrationUtils.SymbolWorkflowStepResponse
|
||||||
? stepOutput.compensateInput &&
|
? stepOutput.compensateInput
|
||||||
deepCopy(stepOutput.compensateInput)
|
: stepOutput
|
||||||
: stepOutput && deepCopy(stepOutput)
|
|
||||||
|
|
||||||
const args = [invokeResult, executionContext]
|
const args = [invokeResult, executionContext]
|
||||||
const output = await compensateFn.apply(this, args)
|
const output = await compensateFn.apply(this, args)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export function proxify<T>(obj: WorkflowData<any>): T {
|
|||||||
return target[prop]
|
return target[prop]
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform(target[prop], async function (input, context) {
|
return transform({}, async function (_, context) {
|
||||||
const { invoke } = context as WorkflowTransactionContext
|
const { invoke } = context as WorkflowTransactionContext
|
||||||
let output =
|
let output =
|
||||||
target.__type === OrchestrationUtils.SymbolInputReference ||
|
target.__type === OrchestrationUtils.SymbolInputReference ||
|
||||||
@@ -19,9 +19,8 @@ export function proxify<T>(obj: WorkflowData<any>): T {
|
|||||||
: invoke?.[obj.__step__]?.output
|
: invoke?.[obj.__step__]?.output
|
||||||
|
|
||||||
output = await resolveValue(output, context)
|
output = await resolveValue(output, context)
|
||||||
output = output?.[prop]
|
|
||||||
|
|
||||||
return output && JSON.parse(JSON.stringify(output))
|
return output?.[prop]
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}) as unknown as T
|
}) as unknown as T
|
||||||
|
|||||||
@@ -3,31 +3,35 @@ import { deepCopy, OrchestrationUtils, promiseAll } from "@medusajs/utils"
|
|||||||
async function resolveProperty(property, transactionContext) {
|
async function resolveProperty(property, transactionContext) {
|
||||||
const { invoke: invokeRes } = transactionContext
|
const { invoke: invokeRes } = transactionContext
|
||||||
|
|
||||||
|
let res
|
||||||
|
|
||||||
if (property?.__type === OrchestrationUtils.SymbolInputReference) {
|
if (property?.__type === OrchestrationUtils.SymbolInputReference) {
|
||||||
return transactionContext.payload
|
res = transactionContext.payload
|
||||||
} else if (
|
} else if (
|
||||||
property?.__type === OrchestrationUtils.SymbolMedusaWorkflowResponse
|
property?.__type === OrchestrationUtils.SymbolMedusaWorkflowResponse
|
||||||
) {
|
) {
|
||||||
return resolveValue(property.$result, transactionContext)
|
res = await resolveValue(property.$result, transactionContext)
|
||||||
} else if (
|
} else if (
|
||||||
property?.__type === OrchestrationUtils.SymbolWorkflowStepTransformer
|
property?.__type === OrchestrationUtils.SymbolWorkflowStepTransformer
|
||||||
) {
|
) {
|
||||||
return await property.__resolver(transactionContext)
|
res = await property.__resolver(transactionContext)
|
||||||
} else if (property?.__type === OrchestrationUtils.SymbolWorkflowStep) {
|
} else if (property?.__type === OrchestrationUtils.SymbolWorkflowStep) {
|
||||||
const output =
|
const output =
|
||||||
invokeRes[property.__step__]?.output ?? invokeRes[property.__step__]
|
invokeRes[property.__step__]?.output ?? invokeRes[property.__step__]
|
||||||
if (output?.__type === OrchestrationUtils.SymbolWorkflowStepResponse) {
|
if (output?.__type === OrchestrationUtils.SymbolWorkflowStepResponse) {
|
||||||
return output.output
|
res = output.output
|
||||||
|
} else {
|
||||||
|
res = output
|
||||||
}
|
}
|
||||||
|
|
||||||
return output
|
|
||||||
} else if (
|
} else if (
|
||||||
property?.__type === OrchestrationUtils.SymbolWorkflowStepResponse
|
property?.__type === OrchestrationUtils.SymbolWorkflowStepResponse
|
||||||
) {
|
) {
|
||||||
return property.output
|
res = property.output
|
||||||
} else {
|
} else {
|
||||||
return property
|
res = property
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,9 +57,8 @@ export async function resolveValue(input, transactionContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const key of Object.keys(inputTOUnwrap)) {
|
for (const key of Object.keys(inputTOUnwrap)) {
|
||||||
parentRef[key] = await resolveProperty(
|
parentRef[key] = deepCopy(
|
||||||
inputTOUnwrap[key],
|
await resolveProperty(inputTOUnwrap[key], transactionContext)
|
||||||
transactionContext
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (typeof parentRef[key] === "object") {
|
if (typeof parentRef[key] === "object") {
|
||||||
@@ -68,8 +71,8 @@ export async function resolveValue(input, transactionContext) {
|
|||||||
|
|
||||||
const copiedInput =
|
const copiedInput =
|
||||||
input?.__type === OrchestrationUtils.SymbolWorkflowWorkflowData
|
input?.__type === OrchestrationUtils.SymbolWorkflowWorkflowData
|
||||||
? deepCopy(input.output)
|
? input.output
|
||||||
: deepCopy(input)
|
: input
|
||||||
|
|
||||||
const result = copiedInput?.__type
|
const result = copiedInput?.__type
|
||||||
? await resolveProperty(copiedInput, transactionContext)
|
? await resolveProperty(copiedInput, transactionContext)
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ import { resolveValue } from "./helpers"
|
|||||||
import { StepExecutionContext, WorkflowData } from "./type"
|
import { StepExecutionContext, WorkflowData } from "./type"
|
||||||
import { proxify } from "./helpers/proxy"
|
import { proxify } from "./helpers/proxy"
|
||||||
import { OrchestrationUtils } from "@medusajs/utils"
|
import { OrchestrationUtils } from "@medusajs/utils"
|
||||||
|
import { ulid } from "ulid"
|
||||||
|
import {
|
||||||
|
TransactionContext,
|
||||||
|
WorkflowStepHandlerArguments,
|
||||||
|
} from "@medusajs/orchestration"
|
||||||
|
|
||||||
type Func1<T extends object | WorkflowData, U> = (
|
type Func1<T extends object | WorkflowData, U> = (
|
||||||
input: T extends WorkflowData<infer U>
|
input: T extends WorkflowData<infer U>
|
||||||
@@ -158,16 +163,26 @@ export function transform(
|
|||||||
values: any | any[],
|
values: any | any[],
|
||||||
...functions: Function[]
|
...functions: Function[]
|
||||||
): unknown {
|
): unknown {
|
||||||
|
const uniqId = ulid()
|
||||||
|
|
||||||
const ret = {
|
const ret = {
|
||||||
|
__id: uniqId,
|
||||||
__type: OrchestrationUtils.SymbolWorkflowStepTransformer,
|
__type: OrchestrationUtils.SymbolWorkflowStepTransformer,
|
||||||
__resolver: undefined,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnFn = async function (transactionContext): Promise<any> {
|
const returnFn = async function (
|
||||||
const allValues = await resolveValue(values, transactionContext)
|
// If a transformer is returned as the result of a workflow, then at this point the workflow is entirely done, in that case we have a TransactionContext
|
||||||
const stepValue = allValues
|
transactionContext: WorkflowStepHandlerArguments | TransactionContext
|
||||||
? JSON.parse(JSON.stringify(allValues))
|
): Promise<any> {
|
||||||
: allValues
|
if ("transaction" in transactionContext) {
|
||||||
|
const temporaryDataKey = `${transactionContext.transaction.modelId}_${transactionContext.transaction.transactionId}_${uniqId}`
|
||||||
|
|
||||||
|
if (transactionContext.transaction.hasTemporaryData(temporaryDataKey)) {
|
||||||
|
return transactionContext.transaction.getTemporaryData(temporaryDataKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepValue = await resolveValue(values, transactionContext)
|
||||||
|
|
||||||
let finalResult
|
let finalResult
|
||||||
for (let i = 0; i < functions.length; i++) {
|
for (let i = 0; i < functions.length; i++) {
|
||||||
@@ -177,6 +192,15 @@ export function transform(
|
|||||||
finalResult = await fn.apply(fn, [arg, transactionContext])
|
finalResult = await fn.apply(fn, [arg, transactionContext])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("transaction" in transactionContext) {
|
||||||
|
const temporaryDataKey = `${transactionContext.transaction.modelId}_${transactionContext.transaction.transactionId}_${uniqId}`
|
||||||
|
|
||||||
|
transactionContext.transaction.setTemporaryData(
|
||||||
|
temporaryDataKey,
|
||||||
|
finalResult
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return finalResult
|
return finalResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,9 +52,9 @@ export function when(input, condition) {
|
|||||||
if (ret?.__type !== OrchestrationUtils.SymbolWorkflowStep) {
|
if (ret?.__type !== OrchestrationUtils.SymbolWorkflowStep) {
|
||||||
const retStep = createStep(
|
const retStep = createStep(
|
||||||
"when-then-" + ulid(),
|
"when-then-" + ulid(),
|
||||||
() => new StepResponse(ret)
|
({ input }: { input: any }) => new StepResponse(input)
|
||||||
)
|
)
|
||||||
returnStep = retStep()
|
returnStep = retStep({ input: ret })
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const step of applyCondition) {
|
for (const step of applyCondition) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const POST = async (
|
|||||||
|
|
||||||
await addToCartWorkflow(req.scope).run({
|
await addToCartWorkflow(req.scope).run({
|
||||||
input: workflowInput,
|
input: workflowInput,
|
||||||
})
|
} as any)
|
||||||
|
|
||||||
const updatedCart = await refetchCart(
|
const updatedCart = await refetchCart(
|
||||||
req.params.id,
|
req.params.id,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export const defaultStoreCartFields = [
|
|||||||
"id",
|
"id",
|
||||||
"currency_code",
|
"currency_code",
|
||||||
"email",
|
"email",
|
||||||
|
"region_id",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"completed_at",
|
"completed_at",
|
||||||
@@ -33,6 +34,7 @@ export const defaultStoreCartFields = [
|
|||||||
"promotions.application_method.type",
|
"promotions.application_method.type",
|
||||||
"promotions.application_method.currency_code",
|
"promotions.application_method.currency_code",
|
||||||
"items.id",
|
"items.id",
|
||||||
|
"items.product.id",
|
||||||
"items.variant_id",
|
"items.variant_id",
|
||||||
"items.product_id",
|
"items.product_id",
|
||||||
"items.product.categories.id",
|
"items.product.categories.id",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ describe("LocalEventBusService", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
|
|
||||||
eventBus = new LocalEventBusService(moduleDeps as any)
|
eventBus = new LocalEventBusService(moduleDeps as any, {}, {} as any)
|
||||||
eventEmitter = (eventBus as any).eventEmitter_
|
eventEmitter = (eventBus as any).eventEmitter_
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
Event,
|
Event,
|
||||||
EventBusTypes,
|
EventBusTypes,
|
||||||
|
InternalModuleDeclaration,
|
||||||
Logger,
|
Logger,
|
||||||
MedusaContainer,
|
MedusaContainer,
|
||||||
Message,
|
Message,
|
||||||
@@ -25,7 +26,11 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
|
|||||||
protected readonly eventEmitter_: EventEmitter
|
protected readonly eventEmitter_: EventEmitter
|
||||||
protected groupedEventsMap_: StagingQueueType
|
protected groupedEventsMap_: StagingQueueType
|
||||||
|
|
||||||
constructor({ logger }: MedusaContainer & InjectedDependencies) {
|
constructor(
|
||||||
|
{ logger }: MedusaContainer & InjectedDependencies,
|
||||||
|
moduleOptions = {},
|
||||||
|
moduleDeclaration: InternalModuleDeclaration
|
||||||
|
) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// eslint-disable-next-line prefer-rest-params
|
// eslint-disable-next-line prefer-rest-params
|
||||||
super(...arguments)
|
super(...arguments)
|
||||||
@@ -54,16 +59,16 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
|
|||||||
eventData.name
|
eventData.name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (eventListenersCount === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.internal && !eventData.options?.internal) {
|
if (!options.internal && !eventData.options?.internal) {
|
||||||
this.logger_?.info(
|
this.logger_?.info(
|
||||||
`Processing ${eventData.name} which has ${eventListenersCount} subscribers`
|
`Processing ${eventData.name} which has ${eventListenersCount} subscribers`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventListenersCount === 0) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.groupOrEmitEvent(eventData)
|
await this.groupOrEmitEvent(eventData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,6 +119,10 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
|
|||||||
}
|
}
|
||||||
|
|
||||||
subscribe(event: string | symbol, subscriber: Subscriber): this {
|
subscribe(event: string | symbol, subscriber: Subscriber): this {
|
||||||
|
if (!this.isWorkerMode) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
const randId = ulid()
|
const randId = ulid()
|
||||||
this.storeSubscribers({ event, subscriberId: randId, subscriber })
|
this.storeSubscribers({ event, subscriberId: randId, subscriber })
|
||||||
this.eventEmitter_.on(event, async (data: Event) => {
|
this.eventEmitter_.on(event, async (data: Event) => {
|
||||||
@@ -133,6 +142,10 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
|
|||||||
subscriber: Subscriber,
|
subscriber: Subscriber,
|
||||||
context?: EventBusTypes.SubscriberContext
|
context?: EventBusTypes.SubscriberContext
|
||||||
): this {
|
): this {
|
||||||
|
if (!this.isWorkerMode) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
const existingSubscribers = this.eventToSubscribersMap_.get(event)
|
const existingSubscribers = this.eventToSubscribersMap_.get(event)
|
||||||
|
|
||||||
if (existingSubscribers?.length) {
|
if (existingSubscribers?.length) {
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Register our worker to handle emit calls
|
// Register our worker to handle emit calls
|
||||||
const shouldStartWorker = moduleDeclaration.worker_mode !== "server"
|
if (this.isWorkerMode) {
|
||||||
if (shouldStartWorker) {
|
|
||||||
this.bullWorker_ = new Worker(
|
this.bullWorker_ = new Worker(
|
||||||
moduleOptions.queueName ?? "events-queue",
|
moduleOptions.queueName ?? "events-queue",
|
||||||
this.worker_,
|
this.worker_,
|
||||||
@@ -116,7 +115,7 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
|
|||||||
// options for a particular event
|
// options for a particular event
|
||||||
...eventData.options,
|
...eventData.options,
|
||||||
},
|
},
|
||||||
}
|
} as any
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-5
@@ -140,13 +140,10 @@ export class InMemoryDistributedTransactionStorage
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const stringifiedData = JSON.stringify(data)
|
|
||||||
const parsedData = JSON.parse(stringifiedData)
|
|
||||||
|
|
||||||
if (hasFinished && !retentionTime && !idempotent) {
|
if (hasFinished && !retentionTime && !idempotent) {
|
||||||
await this.deleteFromDb(parsedData)
|
await this.deleteFromDb(data)
|
||||||
} else {
|
} else {
|
||||||
await this.saveToDb(parsedData)
|
await this.saveToDb(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasFinished) {
|
if (hasFinished) {
|
||||||
|
|||||||
@@ -236,7 +236,6 @@ export class RedisDistributedTransactionStorage
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stringifiedData = JSON.stringify(data)
|
const stringifiedData = JSON.stringify(data)
|
||||||
const parsedData = JSON.parse(stringifiedData)
|
|
||||||
|
|
||||||
if (!hasFinished) {
|
if (!hasFinished) {
|
||||||
if (ttl) {
|
if (ttl) {
|
||||||
@@ -247,9 +246,9 @@ export class RedisDistributedTransactionStorage
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasFinished && !retentionTime && !idempotent) {
|
if (hasFinished && !retentionTime && !idempotent) {
|
||||||
await this.deleteFromDb(parsedData)
|
await this.deleteFromDb(data)
|
||||||
} else {
|
} else {
|
||||||
await this.saveToDb(parsedData)
|
await this.saveToDb(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasFinished) {
|
if (hasFinished) {
|
||||||
|
|||||||
Reference in New Issue
Block a user