diff --git a/server/datalake/src/client.ts b/server/datalake/src/client.ts index e9d5a6005c..ea8374a8ac 100644 --- a/server/datalake/src/client.ts +++ b/server/datalake/src/client.ts @@ -111,16 +111,17 @@ export class DatalakeClient { return (await response.json()) as ListObjectOutput } - async getObject (ctx: MeasureContext, workspace: WorkspaceUuid, objectName: string): Promise { + async getObject (ctx: MeasureContext, workspace: WorkspaceUuid, objectName: string): Promise { const url = this.getObjectUrl(ctx, workspace, objectName) let response try { response = await fetchSafe(ctx, url, { headers: { ...this.headers } }) } catch (err: any) { - if (err.name !== 'NotFoundError') { - console.error('failed to get object', { workspace, objectName, err }) + if (err.name === 'NotFoundError') { + return undefined } + console.error('failed to get object', { workspace, objectName, err }) throw err } @@ -138,7 +139,7 @@ export class DatalakeClient { objectName: string, offset: number, length?: number - ): Promise { + ): Promise { const url = this.getObjectUrl(ctx, workspace, objectName) const headers = { ...this.headers, @@ -149,9 +150,10 @@ export class DatalakeClient { try { response = await fetchSafe(ctx, url, { headers }) } catch (err: any) { - if (err.name !== 'NotFoundError') { - console.error('failed to get partial object', { workspace, objectName, err }) + if (err.name === 'NotFoundError') { + return undefined } + console.error('failed to get partial object', { workspace, objectName, err }) throw err } diff --git a/server/datalake/src/index.ts b/server/datalake/src/index.ts index 94a58c0230..bc5b440be9 100644 --- a/server/datalake/src/index.ts +++ b/server/datalake/src/index.ts @@ -33,6 +33,7 @@ import { import { generateToken } from '@hcengineering/server-token' import { type Readable } from 'stream' import { type UploadObjectParams, DatalakeClient } from './client' +import { NotFoundError } from './error' export { DatalakeClient } @@ -168,7 +169,11 @@ export class DatalakeService implements StorageAdapter { @withContext('get') async get (ctx: MeasureContext, wsIds: WorkspaceIds, objectName: string): Promise { - return await this.retry(ctx, () => this.client.getObject(ctx, wsIds.uuid, objectName)) + const object = await this.retry(ctx, () => this.client.getObject(ctx, wsIds.uuid, objectName)) + if (object === undefined) { + throw new NotFoundError() + } + return object } @withContext('put') @@ -199,8 +204,11 @@ export class DatalakeService implements StorageAdapter { @withContext('read') async read (ctx: MeasureContext, wsIds: WorkspaceIds, objectName: string): Promise { const data = await this.retry(ctx, () => this.client.getObject(ctx, wsIds.uuid, objectName)) - const chunks: Buffer[] = [] + if (data === undefined) { + throw new NotFoundError() + } + const chunks: Buffer[] = [] for await (const chunk of data) { chunks.push(chunk) } @@ -216,7 +224,13 @@ export class DatalakeService implements StorageAdapter { offset: number, length?: number ): Promise { - return await this.retry(ctx, () => this.client.getPartialObject(ctx, wsIds.uuid, objectName, offset, length)) + const object = await this.retry(ctx, () => + this.client.getPartialObject(ctx, wsIds.uuid, objectName, offset, length) + ) + if (object === undefined) { + throw new NotFoundError() + } + return object } async getUrl (ctx: MeasureContext, wsIds: WorkspaceIds, objectName: string): Promise {