🐛 (S3 sync) Fixed cases on storage exception are thrown and preview generation turned off (#782)
This commit is contained in:
@@ -8,41 +8,17 @@ on:
|
||||
- release/*
|
||||
|
||||
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:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
targets: ${{ fromJSON(needs.setup.outputs.targets) }}
|
||||
targets:
|
||||
- backend
|
||||
- frontend
|
||||
- onlyoffice-connector
|
||||
- ldap-sync
|
||||
- nextcloud-migration
|
||||
fail-fast: false
|
||||
needs:
|
||||
- setup
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -1,2 +1,10 @@
|
||||
export class FileNotFountException extends Error {}
|
||||
export class WriteFileException extends Error {}
|
||||
export class FileNotFountException 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
|
||||
const errors = writeResults.filter(result => result.status === "rejected");
|
||||
errors.forEach((error, index) => {
|
||||
const storageId = this.storages[index].getId();
|
||||
logger.error(
|
||||
new OneOfStorageWriteOneFailedException(
|
||||
storageId,
|
||||
`Error writing to storage ${storageId}`,
|
||||
(error as PromiseRejectedResult).reason,
|
||||
),
|
||||
);
|
||||
let errorsCount = 0;
|
||||
writeResults.forEach((result, index) => {
|
||||
if (result.status === "rejected") {
|
||||
const storageId = this.storages[index].getId();
|
||||
logger.error(
|
||||
new OneOfStorageWriteOneFailedException(
|
||||
storageId,
|
||||
path,
|
||||
`Error writing to storage ${storageId}`,
|
||||
(result as PromiseRejectedResult).reason,
|
||||
),
|
||||
);
|
||||
errorsCount++;
|
||||
}
|
||||
});
|
||||
if (errors.length === this.storages.length) {
|
||||
throw new WriteFileException(`Write ${path} failed for all storages`);
|
||||
if (errorsCount === this.storages.length) {
|
||||
throw new WriteFileException(path, `Write ${path} failed for all storages`);
|
||||
}
|
||||
|
||||
const successResult = writeResults.filter(
|
||||
@@ -120,13 +124,14 @@ export class OneOfStorageStrategy implements StorageConnectorAPI {
|
||||
logger.error(
|
||||
new OneOfStorageReadOneFailedException(
|
||||
storage.getId(),
|
||||
path,
|
||||
`Reading ${path} from storage ${storage} failed.`,
|
||||
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> => {
|
||||
for (const storage of this.storages) {
|
||||
if (await storage.exists(path, options)) {
|
||||
return true;
|
||||
try {
|
||||
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;
|
||||
@@ -160,7 +174,7 @@ export class OneOfStorageStrategy implements StorageConnectorAPI {
|
||||
* Throw when read from one of the storages is filed.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ export default class StorageService extends TdriveService<StorageAPI> implements
|
||||
|
||||
async read(path: string, options?: ReadOptions): Promise<Readable> {
|
||||
if (!(await this.exists(path, options))) {
|
||||
throw new FileNotFountException();
|
||||
throw new FileNotFountException(path, "File doesn't exist");
|
||||
}
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
|
||||
@@ -400,7 +400,7 @@ export class DocumentsService {
|
||||
company_id: driveItem.company_id,
|
||||
},
|
||||
context,
|
||||
{ waitForThumbnail: true },
|
||||
{ waitForThumbnail: false },
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -498,7 +498,7 @@ export const getFileMetadata = async (
|
||||
company_id: context.company.id,
|
||||
},
|
||||
context,
|
||||
{ ...(context.user?.server_request ? {} : { waitForThumbnail: true }) },
|
||||
{ ...(context.user?.server_request ? {} : { waitForThumbnail: false }) },
|
||||
);
|
||||
|
||||
if (!file) {
|
||||
|
||||
@@ -63,8 +63,8 @@ export class DocumentsController {
|
||||
chunkNumber: parseInt(q.resumableChunkNumber || q.chunk_number) || 1,
|
||||
filename: q.resumableFilename || q.filename || file?.filename || undefined,
|
||||
type: q.resumableType || q.type || file?.mimetype || undefined,
|
||||
waitForThumbnail: !!q.thumbnail_sync,
|
||||
ignoreThumbnails: false,
|
||||
waitForThumbnail: false,
|
||||
ignoreThumbnails: true,
|
||||
};
|
||||
|
||||
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,
|
||||
filename: q.resumableFilename || q.filename || file?.filename || undefined,
|
||||
type: q.resumableType || q.type || file?.mimetype || undefined,
|
||||
waitForThumbnail: q.thumbnail_sync,
|
||||
ignoreThumbnails: q.ignore_thumbnails,
|
||||
waitForThumbnail: false,
|
||||
ignoreThumbnails: true,
|
||||
};
|
||||
|
||||
const id = request.params.id;
|
||||
|
||||
Reference in New Issue
Block a user