/
vshmidt
/
cloudbeaver
Обзор
Документация
Войти
/
vshmidt
/
cloudbeaver
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
devel
webapp/packages/plugin-data-export/src/ExportFromContainerProcess.ts
139 строк
4 KB
Alexey
refactor: migrate to pure esm CB-5684 (#2929)
21 сен 2024, 07:06
Не верифицирован
21 сен 2024, 07:06
6ad1488
Код
Авторство
О чём код?
/* * CloudBeaver - Cloud Database Manager * Copyright (C) 2020-2024 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ import type { IConnectionInfoParams } from '@cloudbeaver/core-connections'; import type { NotificationService } from '@cloudbeaver/core-events'; import { type AsyncTaskInfo, type DataTransferParameters, GraphQLService, ServerInternalError } from '@cloudbeaver/core-sdk'; import { CancellablePromise, cancellableTimeout, Deferred, EDeferredState } from '@cloudbeaver/core-utils'; const DELAY_BETWEEN_TRIES = 1000; // TODO: seems we need special abstraction over async tasks to manage it export class ExportFromContainerProcess extends Deferred<string> { private taskId?: string; private timeout?: CancellablePromise<void>; private isCancelConfirmed = false; // true when server successfully executed cancelQueryAsync constructor( private readonly graphQLService: GraphQLService, private readonly notificationService: NotificationService, ) { super(); } async start(connectionKey: IConnectionInfoParams, containerNodePath: string, parameters: DataTransferParameters): Promise<string> { // start async task try { const { taskInfo } = await this.graphQLService.sdk.exportDataFromContainer({ projectId: connectionKey.projectId, connectionId: connectionKey.connectionId, containerNodePath, parameters, }); await this.applyResult(taskInfo); this.taskId = taskInfo.id; if (this.getState() === EDeferredState.CANCELLING) { await this.cancelAsync(this.taskId); } this.statusUpdateProcess(); return this.taskId; } catch (e: any) { this.onError(e); throw e; } } /** * this method just mark process as cancelling * to avoid racing conditions the server request will be executed in synchronous manner in start method */ override cancel() { if (this.getState() !== EDeferredState.PENDING) { return; } this.toCancelling(); if (this.timeout) { this.timeout.cancel(); } } private async statusUpdateProcess() { if (this.isFinished || !this.taskId) { return; } // check async task status until execution finished while (this.isInProgress) { if (this.getState() === EDeferredState.CANCELLING) { await this.cancelAsync(this.taskId); } // run the first check immediately because usually the query execution is fast try { const { taskInfo } = await this.graphQLService.sdk.getAsyncTaskInfo({ taskId: this.taskId, removeOnFinish: false, }); await this.applyResult(taskInfo); if (this.isFinished) { return; } } catch (e: any) { this.notificationService.logException(e, 'Failed to check async task status'); } try { this.timeout = cancellableTimeout(DELAY_BETWEEN_TRIES); await this.timeout; } catch {} } } private async cancelAsync(taskId: string) { if (this.isCancelConfirmed) { return; } try { await this.graphQLService.sdk.asyncTaskCancel({ taskId }); this.isCancelConfirmed = true; } catch (e: any) { if (this.getState() === EDeferredState.CANCELLING) { this.toPending(); this.notificationService.logException(e, 'Failed to cancel async task'); } } } private async applyResult(taskInfo: AsyncTaskInfo) { // task is running if (taskInfo.running) { return; } // task failed to execute if (taskInfo.error) { const serverError = new ServerInternalError(taskInfo.error); this.onError(serverError, taskInfo.status); return; } if (!taskInfo.taskResult) { this.onError(new Error('Tasks execution returns no taskResult'), taskInfo.status); return; } // task execution successful this.toResolved(taskInfo.taskResult); await this.graphQLService.sdk.getAsyncTaskInfo({ taskId: taskInfo.id, removeOnFinish: true }); } private onError(error: Error, status?: string) { // if task failed to execute during cancelling - it means it was cancelled successfully if (this.getState() === EDeferredState.CANCELLING) { this.toCancelled(error); } else { this.toRejected(error); } } }