refactor: Run migrations and links sync after loading the app (#8582)

This commit is contained in:
Harminder Virk
2024-08-14 14:09:24 +05:30
committed by GitHub
parent 92a7b5b4c0
commit 19d30df624
6 changed files with 103 additions and 54 deletions
@@ -1,18 +1,16 @@
import express from "express"
import getPort from "get-port"
import { resolve } from "path"
import { isObject, promiseAll, GracefulShutdownServer } from "@medusajs/utils"
import { MedusaContainer } from "@medusajs/types"
import { applyEnvVarsToProcess } from "./utils"
import { promiseAll, GracefulShutdownServer } from "@medusajs/utils"
async function bootstrapApp({
cwd,
env = {},
}: { cwd?: string; env?: Record<any, any> } = {}) {
const app = express()
if (isObject(env)) {
Object.entries(env).forEach(([k, v]) => (process.env[k] = v))
}
applyEnvVarsToProcess(env)
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"
export async function initDb({ env = {} }: { env?: Record<any, any> }) {
if (isObject(env)) {
Object.entries(env).forEach(([k, v]) => (process.env[k] = v))
}
const {
pgConnectionLoader,
logger,
container,
featureFlagsLoader,
MedusaAppLoader,
} = await import("@medusajs/framework")
/**
* Initiates the database connection
*/
export async function initDb() {
const { pgConnectionLoader, featureFlagsLoader } = await import(
"@medusajs/framework"
)
const pgConnection = pgConnectionLoader()
await featureFlagsLoader()
container.register({
[ContainerRegistrationKeys.LOGGER]: asValue(logger),
})
return pgConnection
}
/**
* Migrates the database
*/
export async function migrateDatabase(appLoader: MedusaAppLoader) {
try {
const medusaAppLoader = new MedusaAppLoader()
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")
MedusaModule.clearInstances()
await appLoader.runModulesMigrations()
} catch (err) {
console.error("Something went wrong while running the migrations")
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 { createMedusaContainer } from "@medusajs/utils"
import {
ContainerRegistrationKeys,
createMedusaContainer,
} from "@medusajs/utils"
import { createDatabase, dropDatabase } from "pg-god"
import { getDatabaseURL } from "./database"
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 { applyEnvVarsToProcess } from "./medusa-test-runner-utils/utils"
import { clearInstances } from "./medusa-test-runner-utils/clear-instances"
const axios = require("axios").default
@@ -80,6 +90,7 @@ export function medusaIntegrationTestRunner({
schema = "public",
env = {},
debug = false,
inApp = false,
testSuite,
}: {
moduleName?: string
@@ -87,6 +98,7 @@ export function medusaIntegrationTestRunner({
dbName?: string
schema?: string
debug?: boolean
inApp?: boolean
testSuite: <TService = unknown>(options: MedusaSuiteOptions<TService>) => void
}) {
const tempName = parseInt(process.env.JEST_WORKER_ID || "1")
@@ -104,7 +116,7 @@ export function medusaIntegrationTestRunner({
let shutdown = async () => void 0
const dbUtils = dbTestUtilFactory()
let container: ContainerLike
let globalContainer: ContainerLike
let apiUtils: any
let options = {
@@ -124,7 +136,7 @@ export function medusaIntegrationTestRunner({
},
}
),
getContainer: () => container,
getContainer: () => globalContainer,
dbConfig: {
dbName,
schema,
@@ -137,34 +149,45 @@ export function medusaIntegrationTestRunner({
const beforeAll_ = async () => {
await configLoaderOverride(cwd, dbConfig)
applyEnvVarsToProcess(env)
console.log(`Creating database ${dbName}`)
await dbUtils.create(dbName)
const { logger, container, MedusaAppLoader } = await import(
"@medusajs/framework"
)
const appLoader = new MedusaAppLoader()
container.register({
[ContainerRegistrationKeys.LOGGER]: asValue(logger),
})
try {
dbUtils.pgConnection_ = await initDb({
env,
})
console.log(`Creating database ${dbName}`)
await dbUtils.create(dbName)
dbUtils.pgConnection_ = await initDb()
} catch (error) {
console.error("Error initializing database", error?.message)
throw error
}
let containerRes
let serverShutdownRes
let portRes
console.log(`Migrating database with core migrations and links ${dbName}`)
await migrateDatabase(appLoader)
await syncLinks(appLoader)
await clearInstances()
let containerRes: MedusaContainer = container
let serverShutdownRes: () => any
let portRes: number
try {
const {
shutdown = () => void 0,
container,
container: appContainer,
port,
} = await startApp({
cwd,
env,
})
containerRes = container
containerRes = appContainer
serverShutdownRes = shutdown
portRes = port
} catch (error) {
@@ -172,9 +195,19 @@ export function medusaIntegrationTestRunner({
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()
container = containerRes
globalContainer = containerRes
shutdown = async () => {
await serverShutdownRes()
cancelTokenSource.cancel("Request canceled by shutdown")
@@ -58,11 +58,11 @@ export class RedisDistributedTransactionStorage
async onApplicationPrepareShutdown() {
// Close worker gracefully, i.e. wait for the current jobs to finish
await this.worker.close()
await this.worker?.close()
}
async onApplicationShutdown() {
await this.queue.close()
await this.queue?.close()
}
async onApplicationStart() {