Files
Mangarr/.cursor/rules/jobs.mdc

163 lines
4.7 KiB
Plaintext

---
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