--- description: globs: *.php alwaysApply: false --- # Architecture des Jobs dans Mangarr ## Vue d'ensemble Le système de jobs de Mangarr est conçu pour gérer les tâches asynchrones et de longue durée de manière uniforme à travers tous les domaines. Il est basé sur une architecture centralisée dans le domaine `Shared` et peut être étendu par chaque domaine spécifique. ## Structure ``` src/Domain/Shared/ ├── Domain/ │ ├── Model/ │ │ ├── Job.php # Classe abstraite de base │ │ ├── JobStatus.php # États possibles d'un job │ │ └── FailedJob.php # Représentation d'un job échoué │ ├── Contract/ │ │ ├── JobRepositoryInterface.php │ │ └── FailedJobRepositoryInterface.php │ └── Exception/ │ ├── JobNotFoundException.php │ └── JobNotRetryableException.php └── Infrastructure/ ├── Persistence/ │ ├── Entity/ │ │ ├── JobEntity.php │ │ └── FailedJobEntity.php │ └── Repository/ │ ├── DoctrineJobRepository.php │ └── DoctrineFailedJobRepository.php └── Service/ └── JobRetryService.php ``` ## Cycle de Vie d'un Job ### États Possibles ```php enum JobStatus: string { case PENDING = 'pending'; // Job créé, en attente d'exécution case IN_PROGRESS = 'in_progress';// Job en cours d'exécution case COMPLETED = 'completed'; // Job terminé avec succès case FAILED = 'failed'; // Job échoué définitivement case CANCELLED = 'cancelled'; // Job annulé manuellement } ``` ### Transitions d'États 1. `PENDING` → `IN_PROGRESS` : Lors du démarrage du job 2. `IN_PROGRESS` → `COMPLETED` : Lorsque le job se termine avec succès 3. `IN_PROGRESS` → `FAILED` : Lorsque le job échoue et atteint le nombre maximum de tentatives 4. `IN_PROGRESS` → `PENDING` : Lorsque le job échoue mais peut être réessayé 5. Tout état → `CANCELLED` : Lorsque le job est annulé manuellement ## Création d'un Nouveau Type de Job 1. **Créer une classe de job spécifique** ```php class MyCustomJob extends Job { public function __construct( string $id, public readonly string $someData, public readonly array $additionalData = [] ) { parent::__construct($id, 'my_custom_job'); } } ``` 2. **Définir le Handler** ```php class MyCustomJobHandler { public function __invoke(MyCustomJob $job): void { try { $job->start(); // Logique métier $job->complete(); } catch (\Exception $e) { $job->fail($e->getMessage()); } } } ``` ## Gestion des Échecs ### Retry Automatique - Un job peut être réessayé tant que `$attempts < $maxAttempts` - Lors d'un échec, si des tentatives sont encore possibles, le statut redevient `PENDING` - Les informations d'échec sont conservées dans `FailedJob` ### Informations de Debug Chaque job contient : - `failureReason` : La raison de l'échec - `attempts` : Nombre de tentatives effectuées - `context` : Données contextuelles pour le debug - `createdAt`, `startedAt`, `completedAt` : Timestamps pour le suivi ## Bonnes Pratiques ### 1. Création de Jobs ```php $job = new MyCustomJob( id: Uuid::v4(), someData: 'data', additionalData: ['key' => 'value'] ); ``` ### 2. Gestion du Contexte ```php $job->context['important_info'] = 'value'; $job->context['debug_data'] = $debugInfo; ``` ### 3. Retry Manuel ```php if ($failedJob->canBeRetried()) { $job->attempts = 0; $job->status = JobStatus::PENDING; $jobRepository->save($job); } ``` ### 4. Monitoring - Utiliser `findByStatus()` pour surveiller les jobs par état - Utiliser `findFailedJobs()` pour vérifier les échecs - Consulter `FailedJob` pour les détails des échecs ## Règles Importantes 1. **Idempotence** - Les jobs doivent être idempotents - Gérer les cas de réexécution - Vérifier l'état avant les opérations 2. **Contexte** - Toujours fournir un contexte utile - Inclure les IDs des entités concernées - Ajouter des informations de debug pertinentes 3. **Durée** - Les jobs doivent être de longue durée - Pour les opérations courtes, utiliser des appels directs - Prévoir des timeouts appropriés 4. **Statut** - Ne jamais modifier le statut directement - Utiliser les méthodes `start()`, `complete()`, `fail()`, `cancel()` - Toujours sauvegarder après un changement de statut 5. **Échecs** - Capturer et logger toutes les exceptions - Fournir des messages d'erreur explicites - Conserver le contexte d'échec pour le debug