🐛 (S3 sync) Fixed cases on storage exception are thrown and preview generation turned off (#782)

This commit is contained in:
ericlinagora
2025-01-26 05:33:50 +01:00
committed by GitHub
8 changed files with 53 additions and 55 deletions
+6 -30
View File
@@ -8,41 +8,17 @@ on:
- release/* - release/*
jobs: jobs:
setup:
name: Setup jobs
runs-on: ubuntu-latest
outputs:
targets: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend:
- "tdrive/backend/node/**"
- "tdrive/docker/tdrive-node/Dockerfile"
frontend:
- "tdrive/frontend/**"
- "tdrive/docker/tdrive-frontend/**"
onlyoffice-connector:
- "tdrive/connectors/onlyoffice-connector/**"
- "tdrive/docker/onlyoffice-connector/Dockerfile"
ldap-sync:
- "tdrive/backend/utils/ldap-sync/**"
- "tdrive/docker/tdrive-ldap-sync/Dockerfile"
nextcloud-migration:
- "tdrive/backend/utils/nextcloud-migration/**"
- "tdrive/docker/tdrive-nextcloud-migration/Dockerfile"
publish-feature: publish-feature:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
targets: ${{ fromJSON(needs.setup.outputs.targets) }} targets:
- backend
- frontend
- onlyoffice-connector
- ldap-sync
- nextcloud-migration
fail-fast: false fail-fast: false
needs:
- setup
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -1,2 +1,10 @@
export class FileNotFountException extends Error {} export class FileNotFountException extends Error {
export class WriteFileException extends Error {} constructor(readonly path: string, details: string) {
super(details);
}
}
export class WriteFileException extends Error {
constructor(readonly path: string, details: string) {
super(details);
}
}
@@ -82,19 +82,23 @@ export class OneOfStorageStrategy implements StorageConnectorAPI {
); );
// Log all errors and throw if all write operations fail // Log all errors and throw if all write operations fail
const errors = writeResults.filter(result => result.status === "rejected"); let errorsCount = 0;
errors.forEach((error, index) => { writeResults.forEach((result, index) => {
const storageId = this.storages[index].getId(); if (result.status === "rejected") {
logger.error( const storageId = this.storages[index].getId();
new OneOfStorageWriteOneFailedException( logger.error(
storageId, new OneOfStorageWriteOneFailedException(
`Error writing to storage ${storageId}`, storageId,
(error as PromiseRejectedResult).reason, path,
), `Error writing to storage ${storageId}`,
); (result as PromiseRejectedResult).reason,
),
);
errorsCount++;
}
}); });
if (errors.length === this.storages.length) { if (errorsCount === this.storages.length) {
throw new WriteFileException(`Write ${path} failed for all storages`); throw new WriteFileException(path, `Write ${path} failed for all storages`);
} }
const successResult = writeResults.filter( const successResult = writeResults.filter(
@@ -120,13 +124,14 @@ export class OneOfStorageStrategy implements StorageConnectorAPI {
logger.error( logger.error(
new OneOfStorageReadOneFailedException( new OneOfStorageReadOneFailedException(
storage.getId(), storage.getId(),
path,
`Reading ${path} from storage ${storage} failed.`, `Reading ${path} from storage ${storage} failed.`,
err, err,
), ),
); );
} }
} }
throw new FileNotFountException(`Error reading ${path}`); throw new FileNotFountException(path, `Error reading ${path}`);
}; };
/** /**
@@ -137,8 +142,17 @@ export class OneOfStorageStrategy implements StorageConnectorAPI {
*/ */
exists = async (path: string, options?: ReadOptions): Promise<boolean> => { exists = async (path: string, options?: ReadOptions): Promise<boolean> => {
for (const storage of this.storages) { for (const storage of this.storages) {
if (await storage.exists(path, options)) { try {
return true; if (await storage.exists(path, options)) {
return true;
}
} catch (e) {
throw new OneOfStorageReadOneFailedException(
storage.getId(),
path,
`Reading ${path} from storage ${storage} failed.`,
e,
);
} }
} }
return false; return false;
@@ -160,7 +174,7 @@ export class OneOfStorageStrategy implements StorageConnectorAPI {
* Throw when read from one of the storages is filed. * Throw when read from one of the storages is filed.
*/ */
class StorageException extends Error { class StorageException extends Error {
constructor(readonly storageId: string, details: string, error: Error) { constructor(readonly storageId: string, readonly path: string, details: string, error: Error) {
super(details, error); super(details, error);
} }
} }
@@ -108,7 +108,7 @@ export default class StorageService extends TdriveService<StorageAPI> implements
async read(path: string, options?: ReadOptions): Promise<Readable> { async read(path: string, options?: ReadOptions): Promise<Readable> {
if (!(await this.exists(path, options))) { if (!(await this.exists(path, options))) {
throw new FileNotFountException(); throw new FileNotFountException(path, "File doesn't exist");
} }
try { try {
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
@@ -400,7 +400,7 @@ export class DocumentsService {
company_id: driveItem.company_id, company_id: driveItem.company_id,
}, },
context, context,
{ waitForThumbnail: true }, { waitForThumbnail: false },
); );
} }
@@ -498,7 +498,7 @@ export const getFileMetadata = async (
company_id: context.company.id, company_id: context.company.id,
}, },
context, context,
{ ...(context.user?.server_request ? {} : { waitForThumbnail: true }) }, { ...(context.user?.server_request ? {} : { waitForThumbnail: false }) },
); );
if (!file) { if (!file) {
@@ -63,8 +63,8 @@ export class DocumentsController {
chunkNumber: parseInt(q.resumableChunkNumber || q.chunk_number) || 1, chunkNumber: parseInt(q.resumableChunkNumber || q.chunk_number) || 1,
filename: q.resumableFilename || q.filename || file?.filename || undefined, filename: q.resumableFilename || q.filename || file?.filename || undefined,
type: q.resumableType || q.type || file?.mimetype || undefined, type: q.resumableType || q.type || file?.mimetype || undefined,
waitForThumbnail: !!q.thumbnail_sync, waitForThumbnail: false,
ignoreThumbnails: false, ignoreThumbnails: true,
}; };
createdFile = await globalResolver.services.files.save(null, file, options, context); createdFile = await globalResolver.services.files.save(null, file, options, context);
@@ -29,8 +29,8 @@ export class FileController {
chunkNumber: parseInt(q.resumableChunkNumber || q.chunk_number) || 1, chunkNumber: parseInt(q.resumableChunkNumber || q.chunk_number) || 1,
filename: q.resumableFilename || q.filename || file?.filename || undefined, filename: q.resumableFilename || q.filename || file?.filename || undefined,
type: q.resumableType || q.type || file?.mimetype || undefined, type: q.resumableType || q.type || file?.mimetype || undefined,
waitForThumbnail: q.thumbnail_sync, waitForThumbnail: false,
ignoreThumbnails: q.ignore_thumbnails, ignoreThumbnails: true,
}; };
const id = request.params.id; const id = request.params.id;