1
0
Fork 0
mirror of synced 2024-07-20 05:35:58 +12:00

Merge branch 'master' into fix/aws-session-token-s3-ver2

This commit is contained in:
Michael Drury 2024-06-10 21:56:50 +01:00 committed by GitHub
commit cede6a8a0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 95 additions and 41 deletions

View file

@ -1,4 +1,4 @@
import queue from "./queue" import { getAppMigrationQueue } from "./queue"
import { Next } from "koa" import { Next } from "koa"
import { getAppMigrationVersion } from "./appMigrationMetadata" import { getAppMigrationVersion } from "./appMigrationMetadata"
import { MIGRATIONS } from "./migrations" import { MIGRATIONS } from "./migrations"
@ -37,8 +37,10 @@ export async function checkMissingMigrations(
) { ) {
const currentVersion = await getAppMigrationVersion(appId) const currentVersion = await getAppMigrationVersion(appId)
const latestMigration = getLatestEnabledMigrationId() const latestMigration = getLatestEnabledMigrationId()
const queue = getAppMigrationQueue()
if ( if (
queue &&
latestMigration && latestMigration &&
getTimestamp(currentVersion) < getTimestamp(latestMigration) getTimestamp(currentVersion) < getTimestamp(latestMigration)
) { ) {

View file

@ -12,17 +12,19 @@ export async function processMigrations(
migrations: AppMigration[] migrations: AppMigration[]
) { ) {
console.log(`Processing app migration for "${appId}"`) console.log(`Processing app migration for "${appId}"`)
// have to wrap in context, this gets the tenant from the app ID try {
await context.doInAppContext(appId, async () => { // have to wrap in context, this gets the tenant from the app ID
await locks.doWithLock( await context.doInAppContext(appId, async () => {
{ console.log(`Acquiring app migration lock for "${appId}"`)
name: LockName.APP_MIGRATION, await locks.doWithLock(
type: LockType.AUTO_EXTEND, {
resource: appId, name: LockName.APP_MIGRATION,
}, type: LockType.AUTO_EXTEND,
async () => { resource: appId,
try { },
async () => {
await context.doInAppMigrationContext(appId, async () => { await context.doInAppMigrationContext(appId, async () => {
console.log(`Lock acquired starting app migration for "${appId}"`)
let currentVersion = await getAppMigrationVersion(appId) let currentVersion = await getAppMigrationVersion(appId)
const pendingMigrations = migrations const pendingMigrations = migrations
@ -30,6 +32,9 @@ export async function processMigrations(
.sort((a, b) => a.id.localeCompare(b.id)) .sort((a, b) => a.id.localeCompare(b.id))
const migrationIds = migrations.map(m => m.id).sort() const migrationIds = migrations.map(m => m.id).sort()
console.log(
`App migrations to run for "${appId}" - ${migrationIds.join(",")}`
)
let index = 0 let index = 0
for (const { id, func } of pendingMigrations) { for (const { id, func } of pendingMigrations) {
@ -55,13 +60,13 @@ export async function processMigrations(
currentVersion = id currentVersion = id
} }
}) })
} catch (err) {
logging.logAlert("Failed to run app migration", err)
throw err
} }
} )
)
console.log(`App migration for "${appId}" processed`) console.log(`App migration for "${appId}" processed`)
}) })
} catch (err) {
logging.logAlert("Failed to run app migration", err)
throw err
}
} }

View file

@ -2,23 +2,40 @@ import { queue, logging } from "@budibase/backend-core"
import { Job } from "bull" import { Job } from "bull"
import { MIGRATIONS } from "./migrations" import { MIGRATIONS } from "./migrations"
import { processMigrations } from "./migrationsProcessor" import { processMigrations } from "./migrationsProcessor"
import { apiEnabled } from "../features"
const MAX_ATTEMPTS = 3 const MAX_ATTEMPTS = 1
const appMigrationQueue = queue.createQueue(queue.JobQueue.APP_MIGRATION, { export type AppMigrationJob = {
jobOptions: { appId: string
attempts: MAX_ATTEMPTS, }
removeOnComplete: true,
removeOnFail: true, let appMigrationQueue: queue.Queue<AppMigrationJob> | undefined
},
maxStalledCount: MAX_ATTEMPTS, export function init() {
removeStalledCb: async (job: Job) => { // only run app migrations in main API services
logging.logAlert( if (!apiEnabled()) {
`App migration failed, queue job ID: ${job.id} - reason: ${job.failedReason}` return
) }
}, appMigrationQueue = queue.createQueue<AppMigrationJob>(
}) queue.JobQueue.APP_MIGRATION,
appMigrationQueue.process(processMessage) {
jobOptions: {
attempts: MAX_ATTEMPTS,
removeOnComplete: true,
removeOnFail: true,
},
maxStalledCount: MAX_ATTEMPTS,
removeStalledCb: async (job: Job) => {
logging.logAlert(
`App migration failed, queue job ID: ${job.id} - reason: ${job.failedReason}`
)
},
}
)
return appMigrationQueue.process(processMessage)
}
async function processMessage(job: Job) { async function processMessage(job: Job) {
const { appId } = job.data const { appId } = job.data
@ -26,4 +43,6 @@ async function processMessage(job: Job) {
await processMigrations(appId, MIGRATIONS) await processMigrations(appId, MIGRATIONS)
} }
export default appMigrationQueue export function getAppMigrationQueue() {
return appMigrationQueue
}

View file

@ -3,6 +3,7 @@ import { KoaAdapter } from "@bull-board/koa"
import { queue } from "@budibase/backend-core" import { queue } from "@budibase/backend-core"
import * as automation from "../threads/automation" import * as automation from "../threads/automation"
import { backups } from "@budibase/pro" import { backups } from "@budibase/pro"
import { getAppMigrationQueue } from "../appMigrations/queue"
import { createBullBoard } from "@bull-board/api" import { createBullBoard } from "@bull-board/api"
import BullQueue from "bull" import BullQueue from "bull"
@ -16,10 +17,14 @@ const PATH_PREFIX = "/bulladmin"
export async function init() { export async function init() {
// Set up queues for bull board admin // Set up queues for bull board admin
const backupQueue = backups.getBackupQueue() const backupQueue = backups.getBackupQueue()
const appMigrationQueue = getAppMigrationQueue()
const queues = [automationQueue] const queues = [automationQueue]
if (backupQueue) { if (backupQueue) {
queues.push(backupQueue) queues.push(backupQueue)
} }
if (appMigrationQueue) {
queues.push(appMigrationQueue)
}
const adapters = [] const adapters = []
const serverAdapter: any = new KoaAdapter() const serverAdapter: any = new KoaAdapter()
for (let queue of queues) { for (let queue of queues) {

View file

@ -15,6 +15,7 @@ import * as fileSystem from "../utilities/fileSystem"
import { default as eventEmitter, init as eventInit } from "../events" import { default as eventEmitter, init as eventInit } from "../events"
import * as migrations from "../migrations" import * as migrations from "../migrations"
import * as bullboard from "../automations/bullboard" import * as bullboard from "../automations/bullboard"
import * as appMigrations from "../appMigrations/queue"
import * as pro from "@budibase/pro" import * as pro from "@budibase/pro"
import * as api from "../api" import * as api from "../api"
import sdk from "../sdk" import sdk from "../sdk"
@ -114,6 +115,7 @@ export async function startup(
// configure events to use the pro audit log write // configure events to use the pro audit log write
// can't integrate directly into backend-core due to cyclic issues // can't integrate directly into backend-core due to cyclic issues
queuePromises.push(events.processors.init(pro.sdk.auditLogs.write)) queuePromises.push(events.processors.init(pro.sdk.auditLogs.write))
queuePromises.push(appMigrations.init())
if (automationsEnabled()) { if (automationsEnabled()) {
queuePromises.push(automations.init()) queuePromises.push(automations.init())
} }

View file

@ -1 +1,2 @@
export * from "./environment" export * from "./environment"
export * from "./status"

View file

@ -0,0 +1,11 @@
export type SystemStatusResponse = {
passing?: boolean
checks?: {
login: boolean
search: boolean
}
health?: {
passing: boolean
}
version?: string
}

View file

@ -1,16 +1,24 @@
import { accounts } from "@budibase/backend-core" import { accounts, env as coreEnv } from "@budibase/backend-core"
import { Ctx, SystemStatusResponse } from "@budibase/types"
import env from "../../../environment" import env from "../../../environment"
import { BBContext } from "@budibase/types"
export const fetch = async (ctx: BBContext) => { export const fetch = async (ctx: Ctx<void, SystemStatusResponse>) => {
let status: SystemStatusResponse | undefined
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) { if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
const status = await accounts.getStatus() status = await accounts.getStatus()
ctx.body = status }
} else {
ctx.body = { if (!status) {
status = {
health: { health: {
passing: true, passing: true,
}, },
} }
} }
if (coreEnv.VERSION) {
status.version = coreEnv.VERSION
}
ctx.body = status
} }

View file

@ -27,6 +27,7 @@ describe("/api/system/status", () => {
health: { health: {
passing: true, passing: true,
}, },
version: expect.any(String),
}) })
expect(accounts.getStatus).toHaveBeenCalledTimes(0) expect(accounts.getStatus).toHaveBeenCalledTimes(0)
config.cloudHosted() config.cloudHosted()