Skip to content

Commit

Permalink
UBERF-8310: Optimize backup service
Browse files Browse the repository at this point in the history
1. Optimize backup service backup size calculation
2. Fix cooldown interval
2. remove extra per workspace file logging

Signed-off-by: Andrey Sobolev <[email protected]>
  • Loading branch information
haiodo committed Sep 29, 2024
1 parent 2f0223f commit 0ec5ab9
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 37 deletions.
3 changes: 3 additions & 0 deletions server/backup-service/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface Config extends Omit<BackupConfig, 'Token'> {
Secret: string

Interval: number // Timeout in seconds
CoolDown: number
Timeout: number // Timeout in seconds
BucketName: string
Storage: string // A bucket storage config
Expand All @@ -37,6 +38,7 @@ const envMap: { [key in keyof Config]: string } = {
Secret: 'SECRET',
BucketName: 'BUCKET_NAME',
Interval: 'INTERVAL',
CoolDown: 'COOL_DOWN',
Timeout: 'TIMEOUT',
MongoURL: 'MONGO_URL',
SkipWorkspaces: 'SKIP_WORKSPACES',
Expand All @@ -62,6 +64,7 @@ const config: Config = (() => {
ServiceID: process.env[envMap.ServiceID] ?? 'backup-service',
Interval: parseInt(process.env[envMap.Interval] ?? '3600'),
Timeout: parseInt(process.env[envMap.Timeout] ?? '3600'),
CoolDown: parseInt(process.env[envMap.CoolDown] ?? '300'),
MongoURL: process.env[envMap.MongoURL],
SkipWorkspaces: process.env[envMap.SkipWorkspaces] ?? '',
WorkspaceStorage: process.env[envMap.WorkspaceStorage],
Expand Down
23 changes: 21 additions & 2 deletions server/backup/src/backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1121,10 +1121,27 @@ export async function backup (
}
result.result = true

const sizeFile = 'backup.size.gz'

let sizeInfo: Record<string, number> = {}

if (await storage.exists(sizeFile)) {
sizeInfo = JSON.parse(gunzipSync(await storage.loadFile(sizeFile)).toString())
}
let processed = 0

const addFileSize = async (file: string | undefined | null): Promise<void> => {
if (file != null && (await storage.exists(file))) {
const fileSize = await storage.stat(file)
if (file != null) {
const sz = sizeInfo[file]
const fileSize = sz ?? (await storage.stat(file))
if (sz === undefined) {
sizeInfo[file] = fileSize
}
result.backupSize += fileSize
processed++
if (processed % 10 === 0) {
ctx.info('Calculate size processed', { processed, size: Math.round(result.backupSize / (1024 * 1024)) })
}
}
}

Expand All @@ -1142,6 +1159,8 @@ export async function backup (
}
await addFileSize(infoFile)

await storage.writeFile(sizeFile, gzipSync(JSON.stringify(sizeInfo, undefined, 2), { level: defaultLevel }))

return result
} catch (err: any) {
ctx.error('backup error', { err, workspace: workspaceId.name })
Expand Down
48 changes: 13 additions & 35 deletions server/backup/src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export interface BackupConfig {
Token: string

Interval: number // Timeout in seconds

CoolDown: number // Cooldown in seconds
Timeout: number // Timeout in seconds
BucketName: string
SkipWorkspaces: string
Expand All @@ -67,15 +69,10 @@ class BackupWorker {
) {}

canceled = false
interval: any

async close (): Promise<void> {
this.canceled = true
clearTimeout(this.interval)
}

backupPromise: Promise<void> | undefined

printStats (
ctx: MeasureContext,
stats: { failedWorkspaces: BaseWorkspaceInfo[], processed: number, skipped: number }
Expand All @@ -91,27 +88,14 @@ class BackupWorker {
)
}

async triggerBackup (ctx: MeasureContext): Promise<void> {
const { failedWorkspaces } = await this.backup(ctx)
if (failedWorkspaces.length > 0) {
ctx.info('Failed to backup workspaces, Retry failed workspaces once.', { failed: failedWorkspaces.length })
this.printStats(ctx, await this.doBackup(ctx, failedWorkspaces))
}
}

async schedule (ctx: MeasureContext): Promise<void> {
console.log('schedule timeout for', this.config.Interval, ' seconds')
this.interval = setTimeout(
() => {
if (this.backupPromise !== undefined) {
void this.backupPromise.then(() => {
void this.triggerBackup(ctx)
})
}
void this.triggerBackup(ctx)
},
5 * 60 * 1000
) // Re-check every 5 minutes.
console.log('schedule backup with interval', this.config.Interval, 'seconds')
while (!this.canceled) {
const res = await this.backup(ctx)
this.printStats(ctx, res)
console.log('cool down', this.config.CoolDown, 'seconds')
await new Promise<void>((resolve) => setTimeout(resolve, this.config.CoolDown * 1000))
}
}

async backup (
Expand Down Expand Up @@ -171,11 +155,7 @@ class BackupWorker {
index,
total: workspaces.length
})
const childLogger = rootCtx.logger.childLogger?.(ws.workspace, {
workspace: ws.workspace,
enableConsole: 'true'
})
const ctx = rootCtx.newChild(ws.workspace, { workspace: ws.workspace }, {}, childLogger)
const ctx = rootCtx.newChild(ws.workspace, { workspace: ws.workspace })
let pipeline: Pipeline | undefined
try {
const storage = await createStorageBackupStorage(
Expand Down Expand Up @@ -245,6 +225,8 @@ class BackupWorker {
}
rootCtx.warn('BACKUP STATS', {
workspace: ws.workspace,
workspaceUrl: ws.workspaceUrl,
workspaceName: ws.workspaceName,
index,
...backupInfo,
time: Math.round((Date.now() - st) / 1000),
Expand All @@ -259,7 +241,6 @@ class BackupWorker {
} catch (err: any) {
rootCtx.error('\n\nFAILED to BACKUP', { workspace: ws.workspace, err })
failedWorkspaces.push(ws)
await childLogger?.close()
} finally {
if (pipeline !== undefined) {
await pipeline.close()
Expand Down Expand Up @@ -351,9 +332,6 @@ export function backupService (
void backupWorker.close()
}

void backupWorker.backup(ctx).then((res) => {
backupWorker.printStats(ctx, res)
void backupWorker.schedule(ctx)
})
void backupWorker.schedule(ctx)
return shutdown
}

0 comments on commit 0ec5ab9

Please sign in to comment.