Aller au contenu principal

Gestion des Timeouts - Aaperture

Ce document décrit le système de gestion des timeouts centralisé dans Aaperture.

📋 Vue d'ensemble

Le système de gestion des timeouts permet de configurer des délais d'expiration pour toutes les opérations longues dans l'application, garantissant que les requêtes ne restent pas bloquées indéfiniment.

⚙️ Configuration

📝 Important : Ajoutez ces variables à votre fichier .env pour configurer les timeouts.
Voir ENV_VARIABLES_TIMEOUT.md pour la liste complète et les exemples de configuration.

Tous les timeouts sont configurables via des variables d'environnement avec des valeurs par défaut sensées.

Variables d'environnement disponibles

# Database timeouts (milliseconds)
DB_QUERY_TIMEOUT=30000 # Timeout pour requêtes DB individuelles (défaut: 30s)
DB_CONNECTION_TIMEOUT=10000 # Timeout pour connexions DB (défaut: 10s)
DB_IDLE_TIMEOUT=30000 # Timeout pour connexions idle (défaut: 30s)

# External API timeouts (milliseconds)
GOOGLE_CALENDAR_TIMEOUT=10000 # Timeout pour Google Calendar API (défaut: 10s)
GMAIL_API_TIMEOUT=10000 # Timeout pour Gmail API (défaut: 10s)
GOOGLE_OAUTH_TIMEOUT=10000 # Timeout pour Google OAuth (défaut: 10s)
OPENAI_API_TIMEOUT=30000 # Timeout pour OpenAI API (défaut: 30s)

# Job timeouts (milliseconds)
CRON_JOB_TIMEOUT=300000 # Timeout max pour jobs cron (défaut: 5 minutes)

# HTTP timeouts (milliseconds)
HTTP_REQUEST_TIMEOUT=30000 # Timeout global pour requêtes HTTP (défaut: 30s)

# Infrastructure timeouts (seconds for shell scripts)
MIGRATION_TIMEOUT=600 # Timeout pour migrations (défaut: 10 minutes)
BACKUP_TIMEOUT=1800 # Timeout pour backups (défaut: 30 minutes)

# Other timeouts (milliseconds)
EMAIL_TIMEOUT=30000 # Timeout pour SMTP (défaut: 30s)
WEBSOCKET_TIMEOUT=60000 # Timeout pour WebSocket (défaut: 60s)

🏗️ Architecture

Module de configuration

Le module TimeoutConfig centralise toutes les configurations de timeout :

import { TimeoutConfig } from "../common/timeout.config.js";

constructor(private readonly timeoutConfig: TimeoutConfig) {}

// Utilisation
const timeout = this.timeoutConfig.openaiTimeout; // 30000ms par défaut

Utilitaires

Des fonctions utilitaires sont disponibles pour faciliter l'utilisation des timeouts :

import {
withTimeout,
executeWithTimeoutAndRetry,
} from "../common/timeout.utils.js";

// Timeout simple
const result = await withTimeout(myPromise, 30000, "Operation timed out");

// Timeout avec retry
const result = await executeWithTimeoutAndRetry(
() => myAsyncFunction(),
30000,
3, // max retries
1000, // delay between retries
"Operation timed out"
);

Middleware HTTP

Statut : ✅ Appliqué globalement

Un middleware global applique un timeout à toutes les requêtes HTTP :

// Automatiquement appliqué dans main.ts
// Retourne 408 Request Timeout si le timeout est dépassé

Le middleware TimeoutMiddleware est appliqué dans backend/src/main.ts et utilise HTTP_REQUEST_TIMEOUT (défaut: 30s).

📍 Utilisation par composant

Base de données

Les timeouts de base de données sont configurés dans DbService :

  • Pool connection timeout : DB_CONNECTION_TIMEOUT (défaut: 10s) - ✅ Appliqué
  • Pool idle timeout : DB_IDLE_TIMEOUT (défaut: 30s) - ✅ Appliqué
  • Query timeout : DB_QUERY_TIMEOUT (défaut: 30s) - ✅ Appliqué automatiquement aux requêtes via query()

APIs externes

OpenAI

Statut : ✅ Complètement implémenté

Les timeouts sont configurés via OPENAI_API_TIMEOUT (défaut: 30s) et sont appliqués dans les services suivants :

  • backend/src/agent/agent-chat.service.ts - Timeouts appliqués sur streaming et non-streaming
  • backend/src/agent/agent-actions-generation.service.ts - Timeout appliqué
  • backend/src/search/ai-search.service.ts - Timeouts appliqués sur les 3 appels API (processQuery, generateFilters, answerQuestion)
  • backend/src/search/ai-chat.service.ts - Timeout appliqué
  • backend/src/search/ai-actions.service.ts - Timeout appliqué
  • backend/src/extraction/services/llm.service.ts - Timeout appliqué sur extraction
  • backend/src/openai/openai.service.ts - Timeouts appliqués sur vérification de connexion

Exemple d'implémentation :

import { TimeoutConfig } from "../common/timeout.config.js";
import { withTimeout } from "../common/timeout.utils.js";

@Injectable()
export class MyService {
constructor(private readonly timeoutConfig: TimeoutConfig) {}

async callOpenAI() {
const timeout = this.timeoutConfig.openaiTimeout;
const response = await withTimeout(
openai.chat.completions.create({ ... }),
timeout,
"OpenAI API call timed out"
);
}
}

Google Calendar / Gmail

Statut : ✅ Complètement implémenté

Les timeouts sont configurés via GOOGLE_CALENDAR_TIMEOUT et GMAIL_API_TIMEOUT (défaut: 10s) et sont appliqués dans les services suivants :

  • backend/src/google-calendar/google-calendar.service.ts - Helper withCalendarTimeout utilisé pour tous les appels API (calendars.get/insert/delete, events.list/insert/update/patch/delete/get/instances)
  • backend/src/quotes-invoices/gmail.service.ts - Timeouts appliqués sur users.getProfile et users.messages.send

Exemple d'implémentation :

import { TimeoutConfig } from "../common/timeout.config.js";
import { withTimeout } from "../common/timeout.utils.js";

@Injectable()
export class MyService {
constructor(private readonly timeoutConfig: TimeoutConfig) {}

async callGoogleCalendar() {
const timeout = this.timeoutConfig.googleCalendarTimeout;
const response = await withTimeout(
calendar.events.list({ ... }),
timeout,
"Google Calendar API call timed out"
);
}
}

Jobs Cron

Statut : ✅ Complètement implémenté

Les jobs cron respectent CRON_JOB_TIMEOUT (défaut: 5 minutes). Les schedulers suivants ont été mis à jour :

  • backend/src/audit/audit.scheduler.ts - cleanupOldAuditLogs wrappé avec executeWithTimeoutAndRetry
  • backend/src/sessions/recurring-sessions.scheduler.ts - handleRecurringSessionsGeneration wrappé
  • backend/src/workflow-tasks/workflow-tasks.scheduler.ts - handleWorkflowTasksExecution wrappé
  • backend/src/backup/backup.scheduler.ts - createAutomaticBackup wrappé
  • backend/src/scheduled-emails/scheduled-emails.scheduler.ts - handleScheduledEmailsExecution wrappé
  • backend/src/google-calendar/google-calendar-sync.scheduler.ts - syncCalendarToSessions wrappé
  • backend/src/migrations/migrations.scheduler.ts - checkFailedMigrations wrappé

Exemple d'implémentation :

import { TimeoutConfig } from "../common/timeout.config.js";
import { executeWithTimeoutAndRetry } from "../common/timeout.utils.js";

@Injectable()
export class MyScheduler {
constructor(private readonly timeoutConfig: TimeoutConfig) {}

@Cron(CronExpression.EVERY_DAY_AT_2AM)
async myCronJob() {
await executeWithTimeoutAndRetry(
() => this.doWork(),
this.timeoutConfig.cronJobTimeout,
0, // no retries for cron jobs
0,
"Cron job timed out"
);
}
}

Scripts shell

Migrations

Le script migrate-improved.sh utilise MIGRATION_TIMEOUT :

# Timeout configurable (défaut: 10 minutes)
MIGRATION_TIMEOUT="${MIGRATION_TIMEOUT:-600}"
timeout "${MIGRATION_TIMEOUT}" docker run ...

Backups

Le script backup-db.sh utilise BACKUP_TIMEOUT :

# Timeout configurable (défaut: 30 minutes)
BACKUP_TIMEOUT="${BACKUP_TIMEOUT:-1800}"
timeout "${BACKUP_TIMEOUT}" pg_dump ...

🔍 Monitoring

Les timeouts sont loggés dans les logs de l'application :

  • Timeouts DB : Loggés avec le message "Query timeout after Xms"
  • Timeouts HTTP : Retournent une réponse 408 avec message d'erreur
  • Timeouts scripts : Affichent un message d'erreur et exit avec code 1

🎯 Bonnes pratiques

  1. Utiliser les valeurs par défaut : Les valeurs par défaut sont choisies pour être raisonnables pour la plupart des cas d'usage
  2. Ajuster selon l'environnement : Augmenter les timeouts en production si nécessaire
  3. Surveiller les timeouts : Surveiller les logs pour détecter les timeouts fréquents
  4. Retry avec backoff : Utiliser executeWithTimeoutAndRetry pour les opérations critiques
  5. Timeouts spécifiques : Utiliser des timeouts plus courts pour les opérations rapides, plus longs pour les opérations lourdes
  6. Toujours utiliser TimeoutConfig : Ne jamais hardcoder les valeurs de timeout, toujours utiliser TimeoutConfig pour la configuration centralisée

✅ État d'implémentation

✅ Complètement implémenté

  • Base de données : Timeouts pool et requêtes appliqués dans DbService
  • HTTP : Middleware global appliqué dans main.ts
  • Scripts shell : Timeouts appliqués dans migrate-improved.sh et backup-db.sh
  • APIs externes : Timeouts appliqués dans tous les services :
    • ✅ Services OpenAI (agent-chat.service.ts, ai-search.service.ts, llm.service.ts, openai.service.ts, etc.) - Tous les appels API wrappés avec withTimeout
    • ✅ Services Google Calendar (google-calendar.service.ts) - Helper withCalendarTimeout utilisé pour tous les appels API
    • ✅ Services Gmail (gmail.service.ts) - Timeouts appliqués sur users.getProfile et users.messages.send
  • Jobs cron : Timeouts appliqués dans tous les schedulers :
    • audit.scheduler.ts - cleanupOldAuditLogs wrappé avec executeWithTimeoutAndRetry
    • recurring-sessions.scheduler.ts - handleRecurringSessionsGeneration wrappé
    • workflow-tasks.scheduler.ts - handleWorkflowTasksExecution wrappé
    • backup.scheduler.ts - createAutomaticBackup wrappé
    • scheduled-emails.scheduler.ts - handleScheduledEmailsExecution wrappé
    • google-calendar-sync.scheduler.ts - syncCalendarToSessions wrappé
    • migrations.scheduler.ts - checkFailedMigrations wrappé

Statut : ✅ Tous les timeouts sont maintenant appliqués dans l'application

📚 Références