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

This commit is contained in:
Harminder Virk authored and GitHub committed 2024-08-14 14:09:24 +05:30
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), }
})
/**
* Migrates the database
*/
export async function migrateDatabase(appLoader: MedusaAppLoader) {
try { try {
const medusaAppLoader = new MedusaAppLoader() await appLoader.runModulesMigrations()
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()
} 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() {