chore(modules-sdk): parallel migrations (#13898)
This commit is contained in:
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")
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
Reference in new issue
Block a user