refactor: Run migrations and links sync after loading the app (#8582)
This commit is contained in:
1 parent
92a7b5b4c0
commit
19d30df624
6 files changed
+103
-54
No files matched your search
@@ -1,18 +1,16 @@
|
|||||||
import express from "express"
|
import express from "express"
|
||||||
import getPort from "get-port"
|
import getPort from "get-port"
|
||||||
import { resolve } from "path"
|
import { resolve } from "path"
|
||||||
import { isObject, promiseAll, GracefulShutdownServer } from "@medusajs/utils"
|
|
||||||
import { MedusaContainer } from "@medusajs/types"
|
import { MedusaContainer } from "@medusajs/types"
|
||||||
|
import { applyEnvVarsToProcess } from "./utils"
|
||||||
|
import { promiseAll, GracefulShutdownServer } from "@medusajs/utils"
|
||||||
|
|
||||||
async function bootstrapApp({
|
async function bootstrapApp({
|
||||||
cwd,
|
cwd,
|
||||||
env = {},
|
env = {},
|
||||||
}: { cwd?: string; env?: Record<any, any> } = {}) {
|
}: { cwd?: string; env?: Record<any, any> } = {}) {
|
||||||
const app = express()
|
const app = express()
|
||||||
|
applyEnvVarsToProcess(env)
|
||||||
if (isObject(env)) {
|
|
||||||
Object.entries(env).forEach(([k, v]) => (process.env[k] = v))
|
|
||||||
}
|
|
||||||
|
|
||||||
const loaders = require("@medusajs/medusa/dist/loaders").default
|
const loaders = require("@medusajs/medusa/dist/loaders").default
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* cleanup temporary created resources for the migrations
|
||||||
|
* @internal I didnt find a god place to put that, should we eventually add a close function
|
||||||
|
* to the planner to handle that part? so that you would do planner.close() and it will handle the cleanup
|
||||||
|
* automatically just like we usually do for the classic migrations actions
|
||||||
|
*/
|
||||||
|
export async function clearInstances() {
|
||||||
|
const { MedusaModule } = require("@medusajs/modules-sdk")
|
||||||
|
MedusaModule.clearInstances()
|
||||||
|
}
|
||||||
@@ -1,46 +1,46 @@
|
|||||||
import { ContainerRegistrationKeys, isObject } from "@medusajs/utils"
|
import type { MedusaAppLoader } from "@medusajs/framework"
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/utils"
|
||||||
import { asValue } from "awilix"
|
import { asValue } from "awilix"
|
||||||
|
|
||||||
export async function initDb({ env = {} }: { env?: Record<any, any> }) {
|
/**
|
||||||
if (isObject(env)) {
|
* Initiates the database connection
|
||||||
Object.entries(env).forEach(([k, v]) => (process.env[k] = v))
|
*/
|
||||||
}
|
export async function initDb() {
|
||||||
|
const { pgConnectionLoader, featureFlagsLoader } = await import(
|
||||||
const {
|
"@medusajs/framework"
|
||||||
pgConnectionLoader,
|
)
|
||||||
logger,
|
|
||||||
container,
|
|
||||||
featureFlagsLoader,
|
|
||||||
MedusaAppLoader,
|
|
||||||
} = await import("@medusajs/framework")
|
|
||||||
|
|
||||||
const pgConnection = pgConnectionLoader()
|
const pgConnection = pgConnectionLoader()
|
||||||
await featureFlagsLoader()
|
await featureFlagsLoader()
|
||||||
|
|
||||||
container.register({
|
return pgConnection
|
||||||
[ContainerRegistrationKeys.LOGGER]: asValue(logger),
|
}
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
/**
|
||||||
const medusaAppLoader = new MedusaAppLoader()
|
* Migrates the database
|
||||||
await medusaAppLoader.runModulesMigrations()
|
|
||||||
const planner = await medusaAppLoader.getLinksExecutionPlanner()
|
|
||||||
|
|
||||||
const actionPlan = await planner.createPlan()
|
|
||||||
await planner.executePlan(actionPlan)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* cleanup temporary created resources for the migrations
|
|
||||||
* @internal I didnt find a god place to put that, should we eventually add a close function
|
|
||||||
* to the planner to handle that part? so that you would do planner.close() and it will handle the cleanup
|
|
||||||
* automatically just like we usually do for the classic migrations actions
|
|
||||||
*/
|
*/
|
||||||
const { MedusaModule } = require("@medusajs/modules-sdk")
|
export async function migrateDatabase(appLoader: MedusaAppLoader) {
|
||||||
MedusaModule.clearInstances()
|
try {
|
||||||
|
await appLoader.runModulesMigrations()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Something went wrong while running the migrations")
|
console.error("Something went wrong while running the migrations")
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return pgConnection
|
/**
|
||||||
|
* Syncs links with the databse
|
||||||
|
*/
|
||||||
|
export async function syncLinks(appLoader: MedusaAppLoader) {
|
||||||
|
try {
|
||||||
|
const planner = await appLoader.getLinksExecutionPlanner()
|
||||||
|
const actionPlan = await planner.createPlan()
|
||||||
|
actionPlan.forEach((action) => {
|
||||||
|
console.log(`Sync links: "${action.action}" ${action.tableName}`)
|
||||||
|
})
|
||||||
|
await planner.executePlan(actionPlan)
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Something went wrong while syncing links")
|
||||||
|
throw err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { asValue } from "awilix"
|
||||||
|
import { ContainerRegistrationKeys, isObject } from "@medusajs/utils"
|
||||||
|
|
||||||
|
export function applyEnvVarsToProcess(env?: Record<any, any>) {
|
||||||
|
if (isObject(env)) {
|
||||||
|
Object.entries(env).forEach(([k, v]) => (process.env[k] = v))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,20 @@
|
|||||||
|
import { asValue } from "awilix"
|
||||||
import { ContainerLike, MedusaContainer } from "@medusajs/types"
|
import { ContainerLike, MedusaContainer } from "@medusajs/types"
|
||||||
import { createMedusaContainer } from "@medusajs/utils"
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
createMedusaContainer,
|
||||||
|
} from "@medusajs/utils"
|
||||||
import { createDatabase, dropDatabase } from "pg-god"
|
import { createDatabase, dropDatabase } from "pg-god"
|
||||||
import { getDatabaseURL } from "./database"
|
import { getDatabaseURL } from "./database"
|
||||||
import { startApp } from "./medusa-test-runner-utils/bootstrap-app"
|
import { startApp } from "./medusa-test-runner-utils/bootstrap-app"
|
||||||
import { initDb } from "./medusa-test-runner-utils/use-db"
|
import {
|
||||||
|
initDb,
|
||||||
|
migrateDatabase,
|
||||||
|
syncLinks,
|
||||||
|
} from "./medusa-test-runner-utils/use-db"
|
||||||
import { configLoaderOverride } from "./medusa-test-runner-utils/config"
|
import { configLoaderOverride } from "./medusa-test-runner-utils/config"
|
||||||
|
import { applyEnvVarsToProcess } from "./medusa-test-runner-utils/utils"
|
||||||
|
import { clearInstances } from "./medusa-test-runner-utils/clear-instances"
|
||||||
|
|
||||||
const axios = require("axios").default
|
const axios = require("axios").default
|
||||||
|
|
||||||
@@ -80,6 +90,7 @@ export function medusaIntegrationTestRunner({
|
|||||||
schema = "public",
|
schema = "public",
|
||||||
env = {},
|
env = {},
|
||||||
debug = false,
|
debug = false,
|
||||||
|
inApp = false,
|
||||||
testSuite,
|
testSuite,
|
||||||
}: {
|
}: {
|
||||||
moduleName?: string
|
moduleName?: string
|
||||||
@@ -87,6 +98,7 @@ export function medusaIntegrationTestRunner({
|
|||||||
dbName?: string
|
dbName?: string
|
||||||
schema?: string
|
schema?: string
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
|
inApp?: boolean
|
||||||
testSuite: <TService = unknown>(options: MedusaSuiteOptions<TService>) => void
|
testSuite: <TService = unknown>(options: MedusaSuiteOptions<TService>) => void
|
||||||
}) {
|
}) {
|
||||||
const tempName = parseInt(process.env.JEST_WORKER_ID || "1")
|
const tempName = parseInt(process.env.JEST_WORKER_ID || "1")
|
||||||
@@ -104,7 +116,7 @@ export function medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
let shutdown = async () => void 0
|
let shutdown = async () => void 0
|
||||||
const dbUtils = dbTestUtilFactory()
|
const dbUtils = dbTestUtilFactory()
|
||||||
let container: ContainerLike
|
let globalContainer: ContainerLike
|
||||||
let apiUtils: any
|
let apiUtils: any
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
@@ -124,7 +136,7 @@ export function medusaIntegrationTestRunner({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
getContainer: () => container,
|
getContainer: () => globalContainer,
|
||||||
dbConfig: {
|
dbConfig: {
|
||||||
dbName,
|
dbName,
|
||||||
schema,
|
schema,
|
||||||
@@ -137,34 +149,45 @@ export function medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
const beforeAll_ = async () => {
|
const beforeAll_ = async () => {
|
||||||
await configLoaderOverride(cwd, dbConfig)
|
await configLoaderOverride(cwd, dbConfig)
|
||||||
|
applyEnvVarsToProcess(env)
|
||||||
|
|
||||||
console.log(`Creating database ${dbName}`)
|
const { logger, container, MedusaAppLoader } = await import(
|
||||||
await dbUtils.create(dbName)
|
"@medusajs/framework"
|
||||||
|
)
|
||||||
|
const appLoader = new MedusaAppLoader()
|
||||||
|
container.register({
|
||||||
|
[ContainerRegistrationKeys.LOGGER]: asValue(logger),
|
||||||
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dbUtils.pgConnection_ = await initDb({
|
console.log(`Creating database ${dbName}`)
|
||||||
env,
|
await dbUtils.create(dbName)
|
||||||
})
|
dbUtils.pgConnection_ = await initDb()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error initializing database", error?.message)
|
console.error("Error initializing database", error?.message)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
let containerRes
|
console.log(`Migrating database with core migrations and links ${dbName}`)
|
||||||
let serverShutdownRes
|
await migrateDatabase(appLoader)
|
||||||
let portRes
|
await syncLinks(appLoader)
|
||||||
|
await clearInstances()
|
||||||
|
|
||||||
|
let containerRes: MedusaContainer = container
|
||||||
|
let serverShutdownRes: () => any
|
||||||
|
let portRes: number
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
shutdown = () => void 0,
|
shutdown = () => void 0,
|
||||||
container,
|
container: appContainer,
|
||||||
port,
|
port,
|
||||||
} = await startApp({
|
} = await startApp({
|
||||||
cwd,
|
cwd,
|
||||||
env,
|
env,
|
||||||
})
|
})
|
||||||
|
|
||||||
containerRes = container
|
containerRes = appContainer
|
||||||
serverShutdownRes = shutdown
|
serverShutdownRes = shutdown
|
||||||
portRes = port
|
portRes = port
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -172,9 +195,19 @@ export function medusaIntegrationTestRunner({
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run application migrations and sync links when inside
|
||||||
|
* an application
|
||||||
|
*/
|
||||||
|
if (inApp) {
|
||||||
|
console.log(`Migrating database with core migrations and links ${dbName}`)
|
||||||
|
await migrateDatabase(appLoader)
|
||||||
|
await syncLinks(appLoader)
|
||||||
|
}
|
||||||
|
|
||||||
const cancelTokenSource = axios.CancelToken.source()
|
const cancelTokenSource = axios.CancelToken.source()
|
||||||
|
|
||||||
container = containerRes
|
globalContainer = containerRes
|
||||||
shutdown = async () => {
|
shutdown = async () => {
|
||||||
await serverShutdownRes()
|
await serverShutdownRes()
|
||||||
cancelTokenSource.cancel("Request canceled by shutdown")
|
cancelTokenSource.cancel("Request canceled by shutdown")
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ export class RedisDistributedTransactionStorage
|
|||||||
|
|
||||||
async onApplicationPrepareShutdown() {
|
async onApplicationPrepareShutdown() {
|
||||||
// Close worker gracefully, i.e. wait for the current jobs to finish
|
// Close worker gracefully, i.e. wait for the current jobs to finish
|
||||||
await this.worker.close()
|
await this.worker?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
async onApplicationShutdown() {
|
async onApplicationShutdown() {
|
||||||
await this.queue.close()
|
await this.queue?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
async onApplicationStart() {
|
async onApplicationStart() {
|
||||||
|
|||||||
Reference in new issue
Block a user