feat: add caching debug logs and configurable max concurrent requests for Komga API to enhance performance monitoring

This commit is contained in:
Julien Froidefond
2025-10-18 09:08:41 +02:00
parent ae4b766085
commit b7704207ec
42 changed files with 1141 additions and 1302 deletions

View File

@@ -1,105 +0,0 @@
import type { NextRequest} from "next/server";
import { NextResponse } from "next/server";
import type { RequestTiming } from "@/lib/services/debug.service";
import { DebugService } from "@/lib/services/debug.service";
import { ERROR_CODES } from "@/constants/errorCodes";
import { getErrorMessage } from "@/utils/errors";
import { AppError } from "@/utils/errors";
export async function GET() {
try {
const logs: RequestTiming[] = await DebugService.getRequestLogs();
return NextResponse.json(logs);
} catch (error) {
console.error("Erreur lors de la récupération des logs:", error);
if (error instanceof AppError) {
return NextResponse.json(
{
error: {
code: error.code,
name: "Debug fetch error",
message: getErrorMessage(error.code),
} as AppError,
},
{ status: 500 }
);
}
return NextResponse.json(
{
error: {
code: ERROR_CODES.DEBUG.FETCH_ERROR,
name: "Debug fetch error",
message: getErrorMessage(ERROR_CODES.DEBUG.FETCH_ERROR),
} as AppError,
},
{ status: 500 }
);
}
}
export async function POST(request: NextRequest) {
try {
const timing: RequestTiming = await request.json();
await DebugService.logRequest(timing);
return NextResponse.json({
message: "✅ Log enregistré avec succès",
});
} catch (error) {
console.error("Erreur lors de l'enregistrement du log:", error);
if (error instanceof AppError) {
return NextResponse.json(
{
error: {
code: error.code,
name: "Debug save error",
message: getErrorMessage(error.code),
} as AppError,
},
{ status: 500 }
);
}
return NextResponse.json(
{
error: {
code: ERROR_CODES.DEBUG.SAVE_ERROR,
name: "Debug save error",
message: getErrorMessage(ERROR_CODES.DEBUG.SAVE_ERROR),
} as AppError,
},
{ status: 500 }
);
}
}
export async function DELETE() {
try {
await DebugService.clearLogs();
return NextResponse.json({
message: "🧹 Logs supprimés avec succès",
});
} catch (error) {
console.error("Erreur lors de la suppression des logs:", error);
if (error instanceof AppError) {
return NextResponse.json(
{
error: {
code: error.code,
name: "Debug clear error",
message: getErrorMessage(error.code),
} as AppError,
},
{ status: 500 }
);
}
return NextResponse.json(
{
error: {
code: ERROR_CODES.DEBUG.CLEAR_ERROR,
name: "Debug clear error",
message: getErrorMessage(ERROR_CODES.DEBUG.CLEAR_ERROR),
} as AppError,
},
{ status: 500 }
);
}
}

View File

@@ -8,11 +8,7 @@ export const revalidate = 60;
export async function GET() {
try {
const data = await HomeService.getHomeData();
return NextResponse.json(data, {
headers: {
'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=120'
}
});
return NextResponse.json(data);
} catch (error) {
console.error("API Home - Erreur:", error);
if (error instanceof AppError) {

View File

@@ -4,6 +4,7 @@ import { BookService } from "@/lib/services/book.service";
import { ERROR_CODES } from "@/constants/errorCodes";
import { AppError } from "@/utils/errors";
import { getErrorMessage } from "@/utils/errors";
import { findHttpStatus } from "@/utils/image-errors";
export const dynamic = "force-dynamic";
@@ -18,6 +19,26 @@ export async function GET(
return response;
} catch (error) {
console.error("Erreur lors de la récupération de la page du livre:", error);
// Chercher un status HTTP 404 dans la chaîne d'erreurs
const httpStatus = findHttpStatus(error);
if (httpStatus === 404) {
const { bookId, pageNumber } = await params;
// eslint-disable-next-line no-console
console.log(`📷 Page ${pageNumber} not found for book: ${bookId}`);
return NextResponse.json(
{
error: {
code: ERROR_CODES.IMAGE.FETCH_ERROR,
name: "Image not found",
message: "Image not found",
},
},
{ status: 404 }
);
}
if (error instanceof AppError) {
return NextResponse.json(
{

View File

@@ -4,6 +4,7 @@ import { BookService } from "@/lib/services/book.service";
import { ERROR_CODES } from "@/constants/errorCodes";
import { AppError } from "@/utils/errors";
import { getErrorMessage } from "@/utils/errors";
import { findHttpStatus } from "@/utils/image-errors";
export const dynamic = "force-dynamic";
@@ -32,6 +33,27 @@ export async function GET(
return response;
} catch (error) {
console.error("Erreur lors de la récupération de la miniature de la page:", error);
// Chercher un status HTTP 404 dans la chaîne d'erreurs
const httpStatus = findHttpStatus(error);
if (httpStatus === 404) {
const { bookId, pageNumber: pageNumberParam } = await params;
const pageNumber: number = parseInt(pageNumberParam);
// eslint-disable-next-line no-console
console.log(`📷 Page ${pageNumber} thumbnail not found for book: ${bookId}`);
return NextResponse.json(
{
error: {
code: ERROR_CODES.IMAGE.FETCH_ERROR,
name: "Image not found",
message: "Image not found",
},
},
{ status: 404 }
);
}
if (error instanceof AppError) {
return NextResponse.json(
{

View File

@@ -4,6 +4,7 @@ import { BookService } from "@/lib/services/book.service";
import { ERROR_CODES } from "@/constants/errorCodes";
import { AppError } from "@/utils/errors";
import { getErrorMessage } from "@/utils/errors";
import { findHttpStatus } from "@/utils/image-errors";
export async function GET(
request: NextRequest,
@@ -16,6 +17,26 @@ export async function GET(
return response;
} catch (error) {
console.error("Erreur lors de la récupération de la miniature du livre:", error);
// Chercher un status HTTP 404 dans la chaîne d'erreurs
const httpStatus = findHttpStatus(error);
if (httpStatus === 404) {
const bookId: string = (await params).bookId;
// eslint-disable-next-line no-console
console.log(`📷 Thumbnail not found for book: ${bookId}`);
return NextResponse.json(
{
error: {
code: ERROR_CODES.IMAGE.FETCH_ERROR,
name: "Image not found",
message: "Image not found",
},
},
{ status: 404 }
);
}
if (error instanceof AppError) {
return NextResponse.json(
{

View File

@@ -4,6 +4,7 @@ import { SeriesService } from "@/lib/services/series.service";
import { ERROR_CODES } from "@/constants/errorCodes";
import { AppError } from "@/utils/errors";
import { getErrorMessage } from "@/utils/errors";
import { findHttpStatus } from "@/utils/image-errors";
export const dynamic = "force-dynamic";
@@ -18,6 +19,26 @@ export async function GET(
return response;
} catch (error) {
console.error("Erreur lors de la récupération de la couverture de la série:", error);
// Chercher un status HTTP 404 dans la chaîne d'erreurs
const httpStatus = findHttpStatus(error);
if (httpStatus === 404) {
const seriesId: string = (await params).seriesId;
// eslint-disable-next-line no-console
console.log(`📷 First page image not found for series: ${seriesId}`);
return NextResponse.json(
{
error: {
code: ERROR_CODES.IMAGE.FETCH_ERROR,
name: "Image not found",
message: "Image not found",
},
},
{ status: 404 }
);
}
if (error instanceof AppError) {
return NextResponse.json(
{

View File

@@ -4,6 +4,7 @@ import { SeriesService } from "@/lib/services/series.service";
import { ERROR_CODES } from "@/constants/errorCodes";
import { AppError } from "@/utils/errors";
import { getErrorMessage } from "@/utils/errors";
import { findHttpStatus } from "@/utils/image-errors";
export async function GET(
request: NextRequest,
@@ -15,6 +16,26 @@ export async function GET(
return response;
} catch (error) {
console.error("Erreur lors de la récupération de la miniature de la série:", error);
// Chercher un status HTTP 404 dans la chaîne d'erreurs
const httpStatus = findHttpStatus(error);
if (httpStatus === 404) {
const seriesId: string = (await params).seriesId;
// eslint-disable-next-line no-console
console.log(`📷 Image not found for series: ${seriesId}`);
return NextResponse.json(
{
error: {
code: ERROR_CODES.IMAGE.FETCH_ERROR,
name: "Image not found",
message: "Image not found",
},
},
{ status: 404 }
);
}
if (error instanceof AppError) {
return NextResponse.json(
{