Skip to content

Commit

Permalink
chore(framework): Move and improve workflows loader (medusajs#8363)
Browse files Browse the repository at this point in the history
**What**
Refactoring Workflows loader and move

FIXES FRMW-2627
  • Loading branch information
adrien2p authored Jul 31, 2024
1 parent 22a6296 commit 56602d2
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 42 deletions.
2 changes: 2 additions & 0 deletions packages/framework/framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from "@medusajs/utils"

export default defineConfig({
projectConfig: {
databaseName: "foo",
},
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { defineConfig } from "@medusajs/utils"

export default defineConfig()
30 changes: 30 additions & 0 deletions packages/framework/framework/src/config/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -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")
})
})
3 changes: 1 addition & 2 deletions packages/framework/framework/src/config/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)

/**
Expand Down
1 change: 1 addition & 0 deletions packages/framework/framework/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from "./subscribers"
export * from "./links"
export * from "./jobs"
export * from "./feature-flags"
export * from "./workflows"
22 changes: 13 additions & 9 deletions packages/framework/framework/src/subscribers/subscriber-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export class SubscriberLoader {
* @private
*/
#excludes: RegExp[] = [
/index\.js/,
/index\.ts/,
/\.DS_Store/,
/(\.ts\.map|\.js\.map|\.d\.ts|\.md)/,
/^_[^/\\]*(\.[^/\\]+)?$/,
Expand Down Expand Up @@ -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 fullPath = join(dirPath, entry.name)
const fileEntries = entries.filter((entry) => {
return (
!entry.isDirectory() &&
!this.#excludes.some((exclude) => exclude.test(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)
})
})
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
})
Original file line number Diff line number Diff line change
@@ -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)
})
21 changes: 21 additions & 0 deletions packages/framework/framework/src/workflows/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions packages/framework/framework/src/workflows/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./workflow-loader"
71 changes: 71 additions & 0 deletions packages/framework/framework/src/workflows/workflow-loader.ts
Original file line number Diff line number Diff line change
@@ -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.`)
}
}
22 changes: 0 additions & 22 deletions packages/medusa/src/loaders/helpers/register-workflows.ts

This file was deleted.

18 changes: 9 additions & 9 deletions packages/medusa/src/loaders/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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.
*/
Expand Down Expand Up @@ -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),
})

Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4611,6 +4611,7 @@ __metadata:
dependencies:
"@medusajs/medusa-cli": ^1.3.22
"@medusajs/modules-sdk": ^1.12.11
"@medusajs/orchestration": ^0.5.7
"@medusajs/types": ^1.11.16
"@medusajs/utils": ^1.11.9
"@medusajs/workflows-sdk": ^0.1.6
Expand Down

0 comments on commit 56602d2

Please sign in to comment.