chore(modules-sdk): parallel migrations (#13898)

This commit is contained in:
Carlos R. L. Rodrigues authored and GitHub committed 2025-10-31 11:05:53 -03:00
1 parent fffc1be1e7
commit 13d7d15be5
14 files changed
+124 -24

No files matched your search

@@ -1,12 +1,12 @@
import { MedusaContainer } from "@medusajs/types"
import { Knex } from "../deps/mikro-orm-knex"
import { glob } from "glob"
import { join } from "path"
import { Knex } from "../deps/mikro-orm-knex"
import { logger } from "../logger"
import { ContainerRegistrationKeys } from "../utils"
export abstract class Migrator {
protected abstract migration_table_name: string
export class Migrator {
protected migration_table_name: string
protected container: MedusaContainer
protected pgConnection: Knex<any>
@@ -18,6 +18,7 @@ export abstract class Migrator {
this.pgConnection = this.container.resolve(
ContainerRegistrationKeys.PG_CONNECTION
)
this.migration_table_name = "mikro_orm_migrations"
}
/**
@@ -158,7 +159,21 @@ export abstract class Migrator {
return allScripts
}
protected abstract createMigrationTable(): Promise<void>
abstract run(...args: any[]): Promise<any>
abstract getPendingMigrations(migrationPaths: string[]): Promise<string[]>
protected async createMigrationTable(): Promise<void> {
await this.pgConnection.raw(`
CREATE TABLE IF NOT EXISTS ${this.migration_table_name} (
id serial PRIMARY KEY,
name varchar(255),
executed_at timestamptz DEFAULT CURRENT_TIMESTAMP
)
`)
}
run(...args: any[]): Promise<any> {
throw new Error("Method not implemented")
}
getPendingMigrations(migrationPaths: string[]): Promise<string[]> {
throw new Error("Method not implemented")
}
}
+15 -7
View File
@@ -1,3 +1,4 @@
import { asValue } from "@medusajs/deps/awilix"
import { RemoteFetchDataCallback } from "@medusajs/orchestration"
import {
ConfigModule,
@@ -21,6 +22,7 @@ import {
createMedusaContainer,
discoverFeatureFlagsFromDir,
dynamicImport,
executeWithConcurrency,
FeatureFlag,
GraphQLUtils,
isObject,
@@ -33,7 +35,6 @@ import {
promiseAll,
registerFeatureFlag,
} from "@medusajs/utils"
import { asValue } from "@medusajs/deps/awilix"
import { Link } from "./link"
import {
MedusaModule,
@@ -501,12 +502,14 @@ async function MedusaApp_({
modulesNames: string[]
action?: "run" | "revert" | "generate"
}) => {
const moduleResolutions = modulesNames.map((moduleName) => {
return {
moduleName,
resolution: MedusaModule.getModuleResolutions(moduleName),
const moduleResolutions = Array.from(new Set(modulesNames)).map(
(moduleName) => {
return {
moduleName,
resolution: MedusaModule.getModuleResolutions(moduleName),
}
}
})
)
const missingModules = moduleResolutions
.filter(({ resolution }) => !resolution)
@@ -524,7 +527,7 @@ async function MedusaApp_({
throw error
}
for (const { resolution: moduleResolution } of moduleResolutions) {
const run = async ({ resolution: moduleResolution }) => {
if (
!moduleResolution.options?.database &&
moduleResolution.moduleDeclaration?.scope === MODULE_SCOPE.INTERNAL
@@ -554,6 +557,11 @@ async function MedusaApp_({
await MedusaModule.migrateGenerate(migrationOptions)
}
}
await executeWithConcurrency(
moduleResolutions.map((a) => () => run(a)),
8 // parallel migrations
)
}
const runMigrations: RunMigrationFn = async (): Promise<void> => {
@@ -0,0 +1,31 @@
/**
* Execute functions with a concurrency limit
* @param functions Array of functions to execute in parallel
* @param concurrency Maximum number of concurrent executions
*/
export async function executeWithConcurrency<T>(
functions: (() => Promise<T>)[],
concurrency: number
): Promise<PromiseSettledResult<Awaited<T>>[]> {
const results: PromiseSettledResult<Awaited<T>>[] = new Array(
functions.length
)
let currentIndex = 0
const executeNext = async (): Promise<void> => {
while (currentIndex < functions.length) {
const index = currentIndex++
const result = await Promise.allSettled([functions[index]()])
results[index] = result[0]
}
}
const workers: Promise<void>[] = []
for (let i = 0; i < concurrency; i++) {
workers.push(executeNext())
}
await Promise.all(workers)
return results
}
+1
View File
@@ -19,6 +19,7 @@ export * from "./define-file-config"
export * from "./dynamic-import"
export * from "./env-editor"
export * from "./errors"
export * from "./execute-with-concurrency"
export * from "./file-system"
export * from "./filter-object-by-keys"
export * from "./filter-operator-map"