mirror of
https://github.com/labring/laf.git
synced 2026-02-01 16:57:03 +00:00
feat(server): recover the application and synchronize the recovery functions to sys_db (#1879)
* feat(server): recover the application and synchronize the recovery functions to sys_db --------- Co-authored-by: HUAHUAI23 <lim@outlook.com>
This commit is contained in:
parent
1c688b8afc
commit
46a0cd440f
@ -5,7 +5,12 @@ import { GenerateAlphaNumericPassword } from 'src/utils/random'
|
||||
import { MongoService } from './mongo.service'
|
||||
import * as mongodb_uri from 'mongodb-uri'
|
||||
import { RegionService } from 'src/region/region.service'
|
||||
import { TASK_LOCK_INIT_TIME } from 'src/constants'
|
||||
import {
|
||||
CN_PUBLISHED_CONF,
|
||||
CN_PUBLISHED_FUNCTIONS,
|
||||
CN_PUBLISHED_WEBSITE_HOSTING,
|
||||
TASK_LOCK_INIT_TIME,
|
||||
} from 'src/constants'
|
||||
import { Region } from 'src/region/entities/region'
|
||||
import { SystemDatabase } from '../system-database'
|
||||
import {
|
||||
@ -18,6 +23,9 @@ import { exec } from 'node:child_process'
|
||||
import { promisify } from 'node:util'
|
||||
import { DatabaseSyncRecord } from './entities/database-sync-record'
|
||||
import { MongoClient, ObjectId } from 'mongodb'
|
||||
import { DedicatedDatabaseService } from './dedicated-database/dedicated-database.service'
|
||||
import { CloudFunction } from 'src/function/entities/cloud-function'
|
||||
import { ApplicationConfiguration } from 'src/application/entities/application-configuration'
|
||||
|
||||
const p_exec = promisify(exec)
|
||||
|
||||
@ -29,6 +37,7 @@ export class DatabaseService {
|
||||
constructor(
|
||||
private readonly mongoService: MongoService,
|
||||
private readonly regionService: RegionService,
|
||||
private readonly dedicatedDatabaseService: DedicatedDatabaseService,
|
||||
) {}
|
||||
|
||||
async create(appid: string) {
|
||||
@ -226,11 +235,31 @@ export class DatabaseService {
|
||||
|
||||
async exportDatabase(appid: string, filePath: string, uid: ObjectId) {
|
||||
const region = await this.regionService.findByAppId(appid)
|
||||
const database = await this.findOne(appid)
|
||||
assert(database, 'Database not found')
|
||||
const sharedDatabase = await this.findOne(appid)
|
||||
const dedicatedDatabase = await this.dedicatedDatabaseService.findOne(appid)
|
||||
|
||||
const connectionUri = this.getControlConnectionUri(region, database)
|
||||
assert(connectionUri, 'Database connection uri not found')
|
||||
if (sharedDatabase && dedicatedDatabase) {
|
||||
throw new Error(
|
||||
`Database ${appid} found in both shared and dedicated databases.`,
|
||||
)
|
||||
}
|
||||
|
||||
if (!sharedDatabase && !dedicatedDatabase) {
|
||||
throw new Error(
|
||||
`Database ${appid} not found in both shared and dedicated databases.`,
|
||||
)
|
||||
}
|
||||
let connectionUri
|
||||
if (sharedDatabase) {
|
||||
connectionUri = this.getControlConnectionUri(region, sharedDatabase)
|
||||
} else {
|
||||
connectionUri = await this.dedicatedDatabaseService.getConnectionUri(
|
||||
region,
|
||||
dedicatedDatabase,
|
||||
)
|
||||
}
|
||||
|
||||
assert(connectionUri, `Database ${appid} connection uri not found`)
|
||||
|
||||
try {
|
||||
await p_exec(
|
||||
@ -252,16 +281,39 @@ export class DatabaseService {
|
||||
uid: ObjectId,
|
||||
): Promise<void> {
|
||||
const region = await this.regionService.findByAppId(appid)
|
||||
const database = await this.findOne(appid)
|
||||
assert(database, 'Database not found')
|
||||
|
||||
const connectionUri = this.getControlConnectionUri(region, database)
|
||||
assert(connectionUri, 'Database connection uri not found')
|
||||
const sharedDatabase = await this.findOne(appid)
|
||||
const dedicatedDatabase = await this.dedicatedDatabaseService.findOne(appid)
|
||||
|
||||
if (sharedDatabase && dedicatedDatabase) {
|
||||
throw new Error(
|
||||
`Database ${appid} found in both shared and dedicated databases.`,
|
||||
)
|
||||
}
|
||||
|
||||
if (!sharedDatabase && !dedicatedDatabase) {
|
||||
throw new Error(
|
||||
`Database ${appid} not found in both shared and dedicated databases.`,
|
||||
)
|
||||
}
|
||||
let connectionUri
|
||||
if (sharedDatabase) {
|
||||
connectionUri = this.getControlConnectionUri(region, sharedDatabase)
|
||||
} else {
|
||||
connectionUri = await this.dedicatedDatabaseService.getConnectionUri(
|
||||
region,
|
||||
dedicatedDatabase,
|
||||
)
|
||||
}
|
||||
assert(connectionUri, `Database ${appid} connection uri not found`)
|
||||
|
||||
try {
|
||||
await p_exec(
|
||||
`mongorestore --uri='${connectionUri}' --gzip --archive='${filePath}' --nsFrom="${dbName}.*" --nsTo="${appid}.*" -v --nsInclude="${dbName}.*"`,
|
||||
)
|
||||
|
||||
await this.recoverFunctionsToSystemDatabase(appid, uid)
|
||||
|
||||
await this.db
|
||||
.collection<DatabaseSyncRecord>('DatabaseSyncRecord')
|
||||
.insertOne({ uid, createdAt: new Date() })
|
||||
@ -271,4 +323,54 @@ export class DatabaseService {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async recoverFunctionsToSystemDatabase(appid: string, uid: ObjectId) {
|
||||
const { db, client } =
|
||||
(await this.dedicatedDatabaseService.findAndConnect(appid)) ||
|
||||
(await this.findAndConnect(appid))
|
||||
|
||||
try {
|
||||
const appFunctionCollection = db.collection(CN_PUBLISHED_FUNCTIONS)
|
||||
const appConfCollection = db.collection(CN_PUBLISHED_CONF)
|
||||
const appWebsiteCollection = db.collection(CN_PUBLISHED_WEBSITE_HOSTING)
|
||||
|
||||
const functionsExist = await this.db
|
||||
.collection<CloudFunction>('CloudFunction')
|
||||
.countDocuments({ appid })
|
||||
|
||||
if (functionsExist) {
|
||||
this.logger.debug(`${appid} Functions already exist in system database`)
|
||||
return
|
||||
}
|
||||
|
||||
const funcs: CloudFunction[] = await appFunctionCollection
|
||||
.find<CloudFunction>({})
|
||||
.toArray()
|
||||
|
||||
if (funcs.length === 0) {
|
||||
this.logger.debug(` ${appid} No functions for recover.`)
|
||||
return
|
||||
}
|
||||
|
||||
funcs.forEach((func) => {
|
||||
delete func._id
|
||||
func.appid = appid
|
||||
func.createdBy = uid
|
||||
})
|
||||
|
||||
await this.db.collection<CloudFunction>('CloudFunction').insertMany(funcs)
|
||||
|
||||
// sync conf
|
||||
const conf = await this.db
|
||||
.collection<ApplicationConfiguration>('ApplicationConfiguration')
|
||||
.findOne({ appid })
|
||||
|
||||
await appConfCollection.deleteMany({})
|
||||
await appConfCollection.insertOne(conf)
|
||||
|
||||
await appWebsiteCollection.deleteMany({})
|
||||
} finally {
|
||||
await client.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user