chore(): Workflow engine timers and notification improvements (#13434)
RESOLVES CORE-1177 **What** main changes are: - not blocking execution when notifying - timers management - race condition checks improvements
This commit is contained in:
committed by
GitHub
parent
b776fd55dc
commit
fc4d5f0ac9
@@ -9,11 +9,13 @@ import {
|
||||
import {
|
||||
ContainerLike,
|
||||
Context,
|
||||
Logger,
|
||||
MedusaContainer,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
isString,
|
||||
MedusaError,
|
||||
promiseAll,
|
||||
TransactionState,
|
||||
} from "@medusajs/framework/utils"
|
||||
import {
|
||||
@@ -101,6 +103,7 @@ export class WorkflowOrchestratorService {
|
||||
private subscribers: Subscribers = new Map()
|
||||
private container_: MedusaContainer
|
||||
private inMemoryDistributedTransactionStorage_: InMemoryDistributedTransactionStorage
|
||||
readonly #logger: Logger
|
||||
|
||||
constructor({
|
||||
inMemoryDistributedTransactionStorage,
|
||||
@@ -113,6 +116,10 @@ export class WorkflowOrchestratorService {
|
||||
this.container_ = sharedContainer
|
||||
this.inMemoryDistributedTransactionStorage_ =
|
||||
inMemoryDistributedTransactionStorage
|
||||
|
||||
this.#logger =
|
||||
this.container_.resolve("logger", { allowUnregistered: true }) ?? console
|
||||
|
||||
inMemoryDistributedTransactionStorage.setWorkflowOrchestratorService(this)
|
||||
DistributedTransaction.setStorage(inMemoryDistributedTransactionStorage)
|
||||
WorkflowScheduler.setStorage(inMemoryDistributedTransactionStorage)
|
||||
@@ -673,46 +680,49 @@ export class WorkflowOrchestratorService {
|
||||
}
|
||||
|
||||
private notify(options: NotifyOptions) {
|
||||
const {
|
||||
eventType,
|
||||
workflowId,
|
||||
transactionId,
|
||||
errors,
|
||||
result,
|
||||
step,
|
||||
response,
|
||||
state,
|
||||
} = options
|
||||
// Process subscribers asynchronously to avoid blocking workflow execution
|
||||
setImmediate(() => this.processSubscriberNotifications(options))
|
||||
}
|
||||
|
||||
private async processSubscriberNotifications(options: NotifyOptions) {
|
||||
const { workflowId, transactionId, eventType } = options
|
||||
const subscribers: TransactionSubscribers =
|
||||
this.subscribers.get(workflowId) ?? new Map()
|
||||
|
||||
const notifySubscribers = (handlers: SubscriberHandler[]) => {
|
||||
handlers.forEach((handler) => {
|
||||
handler({
|
||||
eventType,
|
||||
workflowId,
|
||||
transactionId,
|
||||
step,
|
||||
response,
|
||||
result,
|
||||
errors,
|
||||
state,
|
||||
})
|
||||
const notifySubscribersAsync = async (handlers: SubscriberHandler[]) => {
|
||||
const promises = handlers.map(async (handler) => {
|
||||
try {
|
||||
const result = handler(options) as void | Promise<any>
|
||||
if (result && typeof result === "object" && "then" in result) {
|
||||
await (result as Promise<any>)
|
||||
}
|
||||
} catch (error) {
|
||||
this.#logger.error(`Subscriber error: ${error}`)
|
||||
}
|
||||
})
|
||||
|
||||
await promiseAll(promises)
|
||||
}
|
||||
|
||||
const tasks: Promise<void>[] = []
|
||||
|
||||
if (transactionId) {
|
||||
const transactionSubscribers = subscribers.get(transactionId) ?? []
|
||||
notifySubscribers(transactionSubscribers)
|
||||
if (transactionSubscribers.length > 0) {
|
||||
tasks.push(notifySubscribersAsync(transactionSubscribers))
|
||||
}
|
||||
|
||||
if (options.eventType === "onFinish") {
|
||||
if (eventType === "onFinish") {
|
||||
subscribers.delete(transactionId)
|
||||
}
|
||||
}
|
||||
|
||||
const workflowSubscribers = subscribers.get(AnySubscriber) ?? []
|
||||
notifySubscribers(workflowSubscribers)
|
||||
if (workflowSubscribers.length > 0) {
|
||||
tasks.push(notifySubscribersAsync(workflowSubscribers))
|
||||
}
|
||||
|
||||
await promiseAll(tasks)
|
||||
}
|
||||
|
||||
private buildWorkflowEvents({
|
||||
|
||||
@@ -284,36 +284,26 @@ export class WorkflowsModuleService<
|
||||
} as any)
|
||||
}
|
||||
|
||||
@InjectSharedContext()
|
||||
async subscribe(
|
||||
args: {
|
||||
workflowId: string
|
||||
transactionId?: string
|
||||
subscriber: Function
|
||||
subscriberId?: string
|
||||
},
|
||||
@MedusaContext() context: Context = {}
|
||||
) {
|
||||
async subscribe(args: {
|
||||
workflowId: string
|
||||
transactionId?: string
|
||||
subscriber: Function
|
||||
subscriberId?: string
|
||||
}) {
|
||||
return this.workflowOrchestratorService_.subscribe(args as any)
|
||||
}
|
||||
|
||||
@InjectSharedContext()
|
||||
async unsubscribe(
|
||||
args: {
|
||||
workflowId: string
|
||||
transactionId?: string
|
||||
subscriberOrId: string | Function
|
||||
},
|
||||
@MedusaContext() context: Context = {}
|
||||
) {
|
||||
async unsubscribe(args: {
|
||||
workflowId: string
|
||||
transactionId?: string
|
||||
subscriberOrId: string | Function
|
||||
}) {
|
||||
return this.workflowOrchestratorService_.unsubscribe(args as any)
|
||||
}
|
||||
|
||||
@InjectSharedContext()
|
||||
async cancel<TWorkflow extends string | ReturnWorkflow<any, any, any>>(
|
||||
workflowIdOrWorkflow: TWorkflow,
|
||||
options: WorkflowOrchestratorCancelOptions,
|
||||
@MedusaContext() context: Context = {}
|
||||
options: WorkflowOrchestratorCancelOptions
|
||||
) {
|
||||
return await this.workflowOrchestratorService_.cancel(
|
||||
workflowIdOrWorkflow,
|
||||
|
||||
Reference in New Issue
Block a user