chore(framework): Move and improve workflows loader (#8363)
**What** Refactoring Workflows loader and move FIXES FRMW-2627
This commit is contained in:
committed by
GitHub
parent
22a629670b
commit
56602d215b
@@ -13,6 +13,7 @@
|
||||
"./logger": "./dist/logger/index.js",
|
||||
"./database": "./dist/database/index.js",
|
||||
"./subscribers": "./dist/subscribers/index.js",
|
||||
"./workflows": "./dist/workflows/index.js",
|
||||
"./links": "./dist/links/index.js",
|
||||
"./jobs": "./dist/jobs/index.js"
|
||||
},
|
||||
@@ -49,6 +50,7 @@
|
||||
"dependencies": {
|
||||
"@medusajs/medusa-cli": "^1.3.22",
|
||||
"@medusajs/modules-sdk": "^1.12.11",
|
||||
"@medusajs/orchestration": "^0.5.7",
|
||||
"@medusajs/utils": "^1.11.9",
|
||||
"@medusajs/workflows-sdk": "^0.1.6",
|
||||
"awilix": "^8.0.0",
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from "@medusajs/utils"
|
||||
|
||||
export default defineConfig({
|
||||
projectConfig: {
|
||||
databaseName: "foo",
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
import { defineConfig } from "@medusajs/utils"
|
||||
|
||||
export default defineConfig()
|
||||
@@ -0,0 +1,30 @@
|
||||
import { configLoader } from "../loader"
|
||||
import { join } from "path"
|
||||
import { container } from "../../container"
|
||||
import { ContainerRegistrationKeys } from "@medusajs/utils"
|
||||
|
||||
describe("configLoader", () => {
|
||||
const entryDirectory = join(__dirname, "../__fixtures__")
|
||||
|
||||
it("should load the config properly", async () => {
|
||||
let configModule = container.resolve(
|
||||
ContainerRegistrationKeys.CONFIG_MODULE
|
||||
)
|
||||
|
||||
expect(configModule).toBeUndefined()
|
||||
|
||||
configLoader(entryDirectory, "medusa-config.js")
|
||||
|
||||
configModule = container.resolve(ContainerRegistrationKeys.CONFIG_MODULE)
|
||||
|
||||
expect(configModule).toBeDefined()
|
||||
expect(configModule.projectConfig.databaseName).toBeUndefined()
|
||||
|
||||
configLoader(entryDirectory, "medusa-config-2.js")
|
||||
|
||||
configModule = container.resolve(ContainerRegistrationKeys.CONFIG_MODULE)
|
||||
|
||||
expect(configModule).toBeDefined()
|
||||
expect(configModule.projectConfig.databaseName).toBe("foo")
|
||||
})
|
||||
})
|
||||
@@ -13,12 +13,11 @@ const handleConfigError = (error: Error): void => {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// TODO: Later on we could store the config manager into the unique container
|
||||
export const configManager = new ConfigManager()
|
||||
|
||||
container.register(
|
||||
ContainerRegistrationKeys.CONFIG_MODULE,
|
||||
asFunction(() => configManager)
|
||||
asFunction(() => configManager.config)
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,3 +7,4 @@ export * from "./subscribers"
|
||||
export * from "./links"
|
||||
export * from "./jobs"
|
||||
export * from "./feature-flags"
|
||||
export * from "./workflows"
|
||||
|
||||
@@ -33,6 +33,8 @@ export class SubscriberLoader {
|
||||
* @private
|
||||
*/
|
||||
#excludes: RegExp[] = [
|
||||
/index\.js/,
|
||||
/index\.ts/,
|
||||
/\.DS_Store/,
|
||||
/(\.ts\.map|\.js\.map|\.d\.ts|\.md)/,
|
||||
/^_[^/\\]*(\.[^/\\]+)?$/,
|
||||
@@ -129,17 +131,17 @@ export class SubscriberLoader {
|
||||
recursive: true,
|
||||
withFileTypes: true,
|
||||
}).then(async (entries) => {
|
||||
return entries.flatMap(async (entry) => {
|
||||
if (this.#excludes.some((exclude) => exclude.test(entry.name))) {
|
||||
return
|
||||
}
|
||||
const fileEntries = entries.filter((entry) => {
|
||||
return (
|
||||
!entry.isDirectory() &&
|
||||
!this.#excludes.some((exclude) => exclude.test(entry.name))
|
||||
)
|
||||
})
|
||||
|
||||
const fullPath = join(dirPath, entry.name)
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
return await this.createMap(fullPath)
|
||||
}
|
||||
logger.debug(`Registering subscribers from ${dirPath}.`)
|
||||
|
||||
return fileEntries.flatMap(async (entry) => {
|
||||
const fullPath = join(entry.path, entry.name)
|
||||
return await this.createDescriptor(fullPath)
|
||||
})
|
||||
})
|
||||
@@ -237,6 +239,8 @@ export class SubscriberLoader {
|
||||
})
|
||||
}
|
||||
|
||||
logger.debug(`Subscribers registered.`)
|
||||
|
||||
/**
|
||||
* Return the file paths of the registered subscribers, to prevent the
|
||||
* backwards compatible loader from trying to register them.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
|
||||
export const productWorkflowId = "product-notifier-workflow"
|
||||
|
||||
const step = createStep("product-step", () => {
|
||||
return {} as any
|
||||
})
|
||||
|
||||
export const productUpdatedWorkflow = createWorkflow(productWorkflowId, () => {
|
||||
step()
|
||||
return new WorkflowResponse(void 0)
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
|
||||
export const orderWorkflowId = "order-notifier-workflow"
|
||||
|
||||
const step = createStep("order-step", () => {
|
||||
return {} as any
|
||||
})
|
||||
|
||||
export const orderNotifierWorkflow = createWorkflow(orderWorkflowId, () => {
|
||||
step()
|
||||
return new WorkflowResponse(void 0)
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
import { join } from "path"
|
||||
import { WorkflowLoader } from "../workflow-loader"
|
||||
import { WorkflowManager } from "@medusajs/orchestration"
|
||||
import { orderWorkflowId } from "../__fixtures__/workflows/order-notifier"
|
||||
import { productWorkflowId } from "../__fixtures__/workflows/deep-workflows/product-updater"
|
||||
|
||||
describe("WorkflowLoader", () => {
|
||||
const rootDir = join(__dirname, "../__fixtures__", "workflows")
|
||||
|
||||
beforeAll(async () => {
|
||||
await new WorkflowLoader(rootDir).load()
|
||||
})
|
||||
|
||||
it("should register each workflow in the '/workflows' folder and sub folder", async () => {
|
||||
const registeredWorkflows = WorkflowManager.getWorkflows()
|
||||
|
||||
expect(registeredWorkflows.size).toBe(2)
|
||||
expect(registeredWorkflows.has(orderWorkflowId)).toBe(true)
|
||||
expect(registeredWorkflows.has(productWorkflowId)).toBe(true)
|
||||
})
|
||||
})
|
||||
1
packages/framework/framework/src/workflows/index.ts
Normal file
1
packages/framework/framework/src/workflows/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./workflow-loader"
|
||||
@@ -0,0 +1,71 @@
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
import { logger } from "../logger"
|
||||
import { access, readdir } from "fs/promises"
|
||||
import { join } from "path"
|
||||
|
||||
export class WorkflowLoader {
|
||||
/**
|
||||
* The directory from which to load the workflows
|
||||
* @private
|
||||
*/
|
||||
#sourceDir: string | string[]
|
||||
|
||||
/**
|
||||
* The list of file names to exclude from the subscriber scan
|
||||
* @private
|
||||
*/
|
||||
#excludes: RegExp[] = [
|
||||
/index\.js/,
|
||||
/index\.ts/,
|
||||
/\.DS_Store/,
|
||||
/(\.ts\.map|\.js\.map|\.d\.ts|\.md)/,
|
||||
/^_[^/\\]*(\.[^/\\]+)?$/,
|
||||
]
|
||||
|
||||
constructor(sourceDir: string | string[]) {
|
||||
this.#sourceDir = sourceDir
|
||||
}
|
||||
|
||||
/**
|
||||
* Load workflows from the source paths, workflows are registering themselves,
|
||||
* therefore we only need to import them
|
||||
*/
|
||||
async load() {
|
||||
const normalizedSourcePath = Array.isArray(this.#sourceDir)
|
||||
? this.#sourceDir
|
||||
: [this.#sourceDir]
|
||||
|
||||
const promises = normalizedSourcePath.map(async (sourcePath) => {
|
||||
try {
|
||||
await access(sourcePath)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
return await readdir(sourcePath, {
|
||||
recursive: true,
|
||||
withFileTypes: true,
|
||||
}).then(async (entries) => {
|
||||
const fileEntries = entries.filter((entry) => {
|
||||
return (
|
||||
!entry.isDirectory() &&
|
||||
!this.#excludes.some((exclude) => exclude.test(entry.name))
|
||||
)
|
||||
})
|
||||
|
||||
logger.debug(`Registering workflows from ${sourcePath}.`)
|
||||
|
||||
return await promiseAll(
|
||||
fileEntries.map(async (entry) => {
|
||||
const fullPath = join(entry.path, entry.name)
|
||||
return await import(fullPath)
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
await promiseAll(promises)
|
||||
|
||||
logger.debug(`Workflows registered.`)
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { glob } from "glob"
|
||||
import { PluginDetails } from "@medusajs/types"
|
||||
|
||||
/**
|
||||
* import files from the workflows directory to run the registration of the wofklows
|
||||
* @param pluginDetails
|
||||
*/
|
||||
export async function registerWorkflows(
|
||||
plugins: PluginDetails[]
|
||||
): Promise<void> {
|
||||
await Promise.all(
|
||||
plugins.map(async (pluginDetails) => {
|
||||
const files = glob.sync(
|
||||
`${pluginDetails.resolve}/workflows/*.{ts,js,mjs,mts}`,
|
||||
{
|
||||
ignore: ["**/*.d.ts", "**/*.map"],
|
||||
}
|
||||
)
|
||||
return Promise.all(files.map(async (file) => import(file)))
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -13,13 +13,13 @@ import {
|
||||
container,
|
||||
expressLoader,
|
||||
featureFlagsLoader,
|
||||
LinkLoader,
|
||||
JobLoader,
|
||||
LinkLoader,
|
||||
logger,
|
||||
pgConnectionLoader,
|
||||
SubscriberLoader,
|
||||
WorkflowLoader,
|
||||
} from "@medusajs/framework"
|
||||
import { registerWorkflows } from "./helpers/register-workflows"
|
||||
import { getResolvedPlugins } from "./helpers/resolve-plugins"
|
||||
import loadMedusaApp from "./medusa-app"
|
||||
|
||||
@@ -45,6 +45,7 @@ async function subscribersLoader(plugins: PluginDetails[]) {
|
||||
*/
|
||||
await new SubscriberLoader(join(__dirname, "../subscribers")).load()
|
||||
|
||||
// TODO: make it the same as the other loaders, taking an array of paths to load from
|
||||
/**
|
||||
* Load subscribers from all the plugins.
|
||||
*/
|
||||
@@ -121,15 +122,11 @@ async function loadEntrypoints(
|
||||
export async function initializeContainer(
|
||||
rootDirectory: string
|
||||
): Promise<MedusaContainer> {
|
||||
const configModule = configLoader(rootDirectory, "medusa-config.js")
|
||||
const featureFlagRouter = await featureFlagsLoader(
|
||||
join(__dirname, "feature-flags")
|
||||
)
|
||||
configLoader(rootDirectory, "medusa-config.js")
|
||||
await featureFlagsLoader(join(__dirname, "feature-flags"))
|
||||
|
||||
container.register({
|
||||
[ContainerRegistrationKeys.LOGGER]: asValue(logger),
|
||||
[ContainerRegistrationKeys.FEATURE_FLAG_ROUTER]: asValue(featureFlagRouter),
|
||||
[ContainerRegistrationKeys.CONFIG_MODULE]: asValue(configModule),
|
||||
[ContainerRegistrationKeys.REMOTE_QUERY]: asValue(null),
|
||||
})
|
||||
|
||||
@@ -164,7 +161,10 @@ export default async ({
|
||||
container,
|
||||
})
|
||||
|
||||
await registerWorkflows(plugins)
|
||||
const workflowsSourcePaths = plugins.map((p) => join(p.resolve, "workflows"))
|
||||
const workflowLoader = new WorkflowLoader(workflowsSourcePaths)
|
||||
await workflowLoader.load()
|
||||
|
||||
const entrypointsShutdown = await loadEntrypoints(
|
||||
plugins,
|
||||
container,
|
||||
|
||||
Reference in New Issue
Block a user