1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

fix(server): connection aborted logging (#5595)

This commit is contained in:
Jason Rasmussen 2023-12-09 21:46:56 -05:00 committed by GitHub
parent 3a794d7a2b
commit b7b4483a33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 13 deletions

View File

@ -21,6 +21,8 @@ export type Options = {
each?: boolean;
};
export const isConnectionAborted = (error: Error | any) => error.code === 'ECONNABORTED';
export function ValidateUUID({ optional, each }: Options = { optional: false, each: false }) {
return applyDecorators(
IsUUID('4', { each }),

View File

@ -6,6 +6,7 @@ import {
IAccessRepository,
IJobRepository,
ILibraryRepository,
isConnectionAborted,
JobName,
mapAsset,
mimeTypes,
@ -20,6 +21,7 @@ import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import { QueryFailedError } from 'typeorm';
import { promisify } from 'util';
import { IAssetRepository } from './asset-repository';
import { AssetCore } from './asset.core';
import { AssetBulkUploadCheckDto } from './dto/asset-check.dto';
@ -42,6 +44,10 @@ import { CuratedObjectsResponseDto } from './response-dto/curated-objects-respon
type SendFile = Parameters<Response['sendFile']>;
type SendFileOptions = SendFile[1];
// TODO: move file sending logic to an interceptor
const sendFile = (res: Response, path: string, options: SendFileOptions) =>
promisify<string, SendFileOptions>(res.sendFile).bind(res)(path, options);
@Injectable()
export class AssetService {
readonly logger = new Logger(AssetService.name);
@ -336,19 +342,16 @@ export class AssetService {
res.set('Cache-Control', 'private, max-age=86400, no-transform');
res.header('Content-Type', mimeTypes.lookup(filepath));
return new Promise((resolve, reject) => {
res.sendFile(filepath, options, (error: Error) => {
if (!error) {
resolve();
return;
}
if (error.message !== 'Request aborted') {
this.logger.error(`Unable to send file: ${error.name}`, error.stack);
}
reject(error);
});
});
try {
await sendFile(res, filepath, options);
} catch (error: Error | any) {
if (!isConnectionAborted(error)) {
this.logger.error(`Unable to send file: ${error.name}`, error.stack);
}
// throwing closes the connection and prevents `Error: write EPIPE`
throw error;
}
}
private async getLibraryId(authUser: AuthUserDto, libraryId?: string) {

View File

@ -8,6 +8,7 @@ import {
NestInterceptor,
} from '@nestjs/common';
import { Observable, catchError, throwError } from 'rxjs';
import { isConnectionAborted } from '../../domain';
import { routeToErrorMessage } from '../app.utils';
@Injectable()
@ -20,7 +21,9 @@ export class ErrorInterceptor implements NestInterceptor {
throwError(() => {
if (error instanceof HttpException === false) {
const errorMessage = routeToErrorMessage(context.getHandler().name);
this.logger.error(errorMessage, error, error?.errors);
if (!isConnectionAborted(error)) {
this.logger.error(errorMessage, error, error?.errors);
}
return new InternalServerErrorException(errorMessage);
} else {
return error;