From dda0446a7383facc3b5f20d5399668a545d94072 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Fri, 14 Jun 2024 11:50:20 +0700 Subject: [PATCH] UBERF-7266: Fix workspace rate limit (#5812) Signed-off-by: Andrey Sobolev --- server/account-service/src/index.ts | 23 ++++++++------- server/account/src/operations.ts | 43 +++++++++++++++-------------- server/backup/src/backup.ts | 17 ++++++++++-- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/server/account-service/src/index.ts b/server/account-service/src/index.ts index 200176c80c..8e28487777 100644 --- a/server/account-service/src/index.ts +++ b/server/account-service/src/index.ts @@ -106,16 +106,19 @@ export function serveAccount ( // We need to clean workspace with creating === true, since server is restarted. void cleanInProgressWorkspaces(db, productId) - worker = new UpgradeWorker(db, p, version, txes, migrateOperations, productId) - await worker.upgradeAll(measureCtx, { - errorHandler: async (ws, err) => { - Analytics.handleError(err) - }, - force: false, - console: false, - logs: 'upgrade-logs', - parallel: parseInt(process.env.PARALLEL ?? '1') - }) + const performUpgrade = (process.env.PERFORM_UPGRADE ?? 'true') === 'true' + if (performUpgrade) { + worker = new UpgradeWorker(db, p, version, txes, migrateOperations, productId) + await worker.upgradeAll(measureCtx, { + errorHandler: async (ws, err) => { + Analytics.handleError(err) + }, + force: false, + console: false, + logs: 'upgrade-logs', + parallel: parseInt(process.env.PARALLEL ?? '1') + }) + } }) const extractToken = (header: IncomingHttpHeaders): string | undefined => { diff --git a/server/account/src/operations.ts b/server/account/src/operations.ts index 1e68c4adec..170ee32789 100644 --- a/server/account/src/operations.ts +++ b/server/account/src/operations.ts @@ -886,7 +886,7 @@ async function generateWorkspaceRecord ( let searchPromise: Promise | undefined -const rateLimiter = new RateLimiter(3) +const rateLimiter = new RateLimiter(parseInt(process.env.RATELIMIT ?? '10')) /** * @public @@ -905,26 +905,26 @@ export async function createWorkspace ( notifyHandler?: (workspace: Workspace) => void, postInitHandler?: (workspace: Workspace, model: Tx[]) => Promise ): Promise<{ workspaceInfo: Workspace, err?: any, model?: Tx[] }> { + // We need to search for duplicate workspaceUrl + await searchPromise + + // Safe generate workspace record. + searchPromise = generateWorkspaceRecord(db, email, productId, version, workspaceName, workspace) + + const workspaceInfo = await searchPromise + + notifyHandler?.(workspaceInfo) + + const wsColl = db.collection>(WORKSPACE_COLLECTION) + + async function updateInfo (ops: Partial): Promise { + await wsColl.updateOne({ _id: workspaceInfo._id }, { $set: ops }) + console.log('update', ops) + } + + await updateInfo({ createProgress: 10 }) + return await rateLimiter.exec(async () => { - // We need to search for duplicate workspaceUrl - await searchPromise - - // Safe generate workspace record. - searchPromise = generateWorkspaceRecord(db, email, productId, version, workspaceName, workspace) - - const workspaceInfo = await searchPromise - - notifyHandler?.(workspaceInfo) - - const wsColl = db.collection>(WORKSPACE_COLLECTION) - - async function updateInfo (ops: Partial): Promise { - await wsColl.updateOne({ _id: workspaceInfo._id }, { $set: ops }) - console.log('update', ops) - } - - await updateInfo({ createProgress: 10 }) - const childLogger = ctx.newChild('createWorkspace', { workspace: workspaceInfo.workspace }) const ctxModellogger: ModelLogger = { log: (msg, data) => { @@ -959,7 +959,8 @@ export async function createWorkspace ( true, async (value) => { await updateInfo({ createProgress: 20 + Math.round((Math.min(value, 100) / 100) * 30) }) - } + }, + true ) await updateInfo({ createProgress: 50 }) model = await upgradeModel( diff --git a/server/backup/src/backup.ts b/server/backup/src/backup.ts index 7de491fde1..d7580cc5cc 100644 --- a/server/backup/src/backup.ts +++ b/server/backup/src/backup.ts @@ -20,6 +20,7 @@ import core, { Client as CoreClient, Doc, Domain, + DOMAIN_FULLTEXT_BLOB, DOMAIN_MODEL, DOMAIN_TRANSIENT, MeasureContext, @@ -29,7 +30,8 @@ import core, { SortingOrder, TxCollectionCUD, WorkspaceId, - type Blob + type Blob, + type DocIndexState } from '@hcengineering/core' import { BlobClient, connect } from '@hcengineering/server-tool' import { createGzip } from 'node:zlib' @@ -223,7 +225,8 @@ export async function cloneWorkspace ( sourceWorkspaceId: WorkspaceId, targetWorkspaceId: WorkspaceId, clearTime: boolean = true, - progress: (value: number) => Promise + progress: (value: number) => Promise, + skipFullText: boolean ): Promise { const sourceConnection = (await connect(transactorUrl, sourceWorkspaceId, undefined, { mode: 'backup' @@ -245,6 +248,10 @@ export async function cloneWorkspace ( let i = 0 for (const c of domains) { + if (skipFullText && c === DOMAIN_FULLTEXT_BLOB) { + console.log('clone skip domain...', c) + continue + } console.log('clone domain...', c) // We need to clean target connection before copying something. @@ -321,6 +328,12 @@ export async function cloneWorkspace ( } catch (err: any) { console.log(err) } + + // if full text is skipped, we need to clean stages for indexes. + if (p._class === core.class.DocIndexState && skipFullText) { + ;(p as DocIndexState).stages = {} + } + if (collectionCud) { return { ...p,