@volontariapp/post-processors 3.2.7 → 3.2.10-snap-d0fb360
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/README.md +46 -46
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.2.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies []:
|
|
8
|
+
- @volontariapp/messaging@2.10.3
|
|
9
|
+
- @volontariapp/database@3.4.6
|
|
10
|
+
- @volontariapp/outbox@0.9.43
|
|
11
|
+
|
|
12
|
+
## 3.2.9
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- README bump
|
|
17
|
+
|
|
18
|
+
- Updated dependencies []:
|
|
19
|
+
- @volontariapp/messaging@2.10.2
|
|
20
|
+
- @volontariapp/logger@0.2.7
|
|
21
|
+
- @volontariapp/database@3.4.5
|
|
22
|
+
- @volontariapp/outbox@0.9.42
|
|
23
|
+
- @volontariapp/health-check@1.0.6
|
|
24
|
+
|
|
25
|
+
## 3.2.8
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- README bump
|
|
30
|
+
|
|
31
|
+
- Updated dependencies []:
|
|
32
|
+
- @volontariapp/database@3.4.4
|
|
33
|
+
- @volontariapp/health-check@1.0.5
|
|
34
|
+
- @volontariapp/logger@0.2.6
|
|
35
|
+
- @volontariapp/messaging@2.10.1
|
|
36
|
+
- @volontariapp/outbox@0.9.41
|
|
37
|
+
- @volontariapp/shared@0.8.1
|
|
38
|
+
|
|
3
39
|
## 3.2.7
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# Post-Processors
|
|
1
|
+
# Package Post-Processors
|
|
2
2
|
|
|
3
|
-
## Overview
|
|
3
|
+
## Aperçu (Overview)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Le package `post-processors` fournit une fondation robuste, scalable et résiliente pour le traitement asynchrone des événements via Redis Streams. Il est conçu pour gérer une consommation d'événements à haut débit avec une tolérance aux pannes intégrée, un traitement par lots dynamique (batching), un disjoncteur (circuit breaker), de l'idempotence et la gestion des files d'attente de lettres mortes (DLQ).
|
|
6
6
|
|
|
7
7
|
## Architecture
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
L'architecture est construite autour d'une classe abstraite de base qui gère l'orchestration complexe des Redis Streams, permettant aux développeurs de se concentrer uniquement sur la logique métier du traitement des événements (un par un ou par lots).
|
|
10
10
|
|
|
11
11
|
```mermaid
|
|
12
12
|
classDiagram
|
|
@@ -31,67 +31,67 @@ classDiagram
|
|
|
31
31
|
BasePostProcessor <|-- BatchPostProcessor
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
###
|
|
34
|
+
### Types de Traitement
|
|
35
35
|
|
|
36
|
-
1. **SinglePostProcessor
|
|
37
|
-
2. **BatchPostProcessor
|
|
36
|
+
1. **SinglePostProcessor** : Traite les événements séquentiellement, un par un. Idéal pour les opérations qui ne peuvent pas être traitées par lots (ex: envoi d'emails individuels) ou lorsqu'une isolation stricte entre les événements est requise.
|
|
37
|
+
2. **BatchPostProcessor** : Accumule un lot d'événements et les traite ensemble. Fortement recommandé pour les opérations I/O (comme les insertions en base de données ou les appels d'API en masse) afin de maximiser le débit et minimiser la latence.
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Mécanismes Internes et Boucles
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Pour garantir qu'aucun événement ne soit perdu ou bloqué de façon permanente, le `BasePostProcessor` orchestre quatre boucles parallèles en arrière-plan.
|
|
42
42
|
|
|
43
43
|
```mermaid
|
|
44
44
|
graph TD
|
|
45
45
|
RedisStream[(Redis Stream)]
|
|
46
46
|
|
|
47
|
-
subgraph Loops [Post-
|
|
47
|
+
subgraph Loops [Boucles des Post-Processors]
|
|
48
48
|
RL[RunLoop]
|
|
49
49
|
CL[ClaimLoop]
|
|
50
50
|
Retry[RetryLoop]
|
|
51
51
|
DLQSync[DlqSyncLoop]
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
RL -->|
|
|
55
|
-
CL -->|
|
|
56
|
-
Retry -->|
|
|
57
|
-
DLQSync -->|
|
|
54
|
+
RL -->|Lit les messages nouveaux/en attente| RedisStream
|
|
55
|
+
CL -->|Trouve les messages en attente isolés et les réclame| RedisStream
|
|
56
|
+
Retry -->|Signale les retries prêts à la RunLoop| RL
|
|
57
|
+
DLQSync -->|Nettoie les vieilles entrées DLQ| RedisStream
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
- **RunLoop
|
|
61
|
-
- **ClaimLoop
|
|
62
|
-
- **RetryLoop
|
|
63
|
-
- **DlqSyncLoop
|
|
60
|
+
- **RunLoop** : La boucle de consommation principale. Elle interroge continuellement le flux Redis pour de nouveaux messages avec `XREADGROUP`. Elle ajuste dynamiquement la taille des lots en fonction de la mémoire système, de la charge CPU et de la latence de traitement.
|
|
61
|
+
- **ClaimLoop** : Un mécanisme de récupération. Elle scanne le groupe de consommateurs à la recherche de messages qui sont restés "en attente" (assignés à un consommateur) trop longtemps. Cela se produit si un consommateur plante avant d'acquitter (ACK) un message. La boucle réclame ces messages orphelins pour qu'ils soient traités par un consommateur sain.
|
|
62
|
+
- **RetryLoop** : Gère les nouvelles tentatives différées (retries). Lorsque le traitement échoue, le message est planifié pour une nouvelle tentative avec un backoff exponentiel. Cette boucle détecte quand le temps d'attente est écoulé et demande à la RunLoop de récupérer à nouveau le message.
|
|
63
|
+
- **DlqSyncLoop** : Gère la Dead Letter Queue (DLQ). Les messages qui épuisent toutes leurs tentatives de retry sont déplacés vers la DLQ. Cette boucle nettoie périodiquement les entrées DLQ expirées selon la politique de rétention pour éviter l'épuisement de la mémoire dans Redis.
|
|
64
64
|
|
|
65
|
-
##
|
|
65
|
+
## Tolérance aux Pannes et Idempotence
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
Le package inclut des mécanismes complets pour gérer gracieusement les défaillances.
|
|
68
68
|
|
|
69
|
-
### Circuit Breaker
|
|
69
|
+
### Pattern Circuit Breaker (Disjoncteur)
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
1. **
|
|
73
|
-
2. **
|
|
71
|
+
Dans les systèmes distribués, un post-processor dépend souvent de services externes (bases de données, API tierces, autres microservices). Lorsque ces services en aval subissent une dégradation ou échouent totalement, continuer à envoyer des requêtes peut entraîner des défaillances en cascade :
|
|
72
|
+
1. **Épuisement des Ressources** : Le post-processor gaspille du CPU, de la mémoire et des connexions réseau à attendre des timeouts.
|
|
73
|
+
2. **Surcharge du Système** : Le service en difficulté est matraqué de trafic qu'il ne peut pas gérer, ce qui l'empêche de récupérer.
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
Pour protéger à la fois le post-processor et les systèmes en aval, le `BasePostProcessor` implémente le pattern **Circuit Breaker**. Il surveille les taux de succès et d'échec du traitement des événements.
|
|
76
76
|
|
|
77
77
|
```mermaid
|
|
78
78
|
stateDiagram-v2
|
|
79
79
|
[*] --> Closed
|
|
80
80
|
|
|
81
|
-
Closed --> Open:
|
|
82
|
-
Open --> HalfOpen:
|
|
81
|
+
Closed --> Open: Seuil d'échec atteint
|
|
82
|
+
Open --> HalfOpen: Période de refroidissement écoulée
|
|
83
83
|
|
|
84
|
-
HalfOpen --> Closed:
|
|
85
|
-
HalfOpen --> Open:
|
|
84
|
+
HalfOpen --> Closed: Succès (Service rétabli)
|
|
85
|
+
HalfOpen --> Open: Échec (Service toujours hors ligne)
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
####
|
|
88
|
+
#### Comment ça marche :
|
|
89
89
|
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
90
|
+
- **État Fermé (Fonctionnement Normal)** : Le circuit est fermé, permettant à l'électricité (messages) de circuler. La `RunLoop` récupère et traite les événements normalement. Le disjoncteur compte les échecs récents.
|
|
91
|
+
- **État Ouvert (Défaillance Détectée)** : Si le taux d'échec dépasse un seuil prédéfini dans une fenêtre de temps spécifique, le circuit "saute" et s'ouvre. La `RunLoop` suspend immédiatement la récupération de nouveaux messages. Cela donne au service défaillant le temps de récupérer sans être surchargé.
|
|
92
|
+
- **État Semi-Ouvert (Test de Récupération)** : Après une période de refroidissement (cooldown), le circuit passe dans un état semi-ouvert. Il laisse passer un nombre limité de messages de test.
|
|
93
|
+
- Si ces messages réussissent, le circuit suppose que le service en aval est de nouveau sain et repasse à l'**État Fermé**.
|
|
94
|
+
- Si les messages échouent, le circuit repasse immédiatement à l'**État Ouvert** pour une autre période de refroidissement.
|
|
95
95
|
|
|
96
96
|
```mermaid
|
|
97
97
|
sequenceDiagram
|
|
@@ -117,16 +117,16 @@ sequenceDiagram
|
|
|
117
117
|
end
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
###
|
|
121
|
-
- **
|
|
122
|
-
- **Circuit Breaker
|
|
123
|
-
- **
|
|
120
|
+
### Fonctionnalités Clés
|
|
121
|
+
- **Idempotence** : Utilise des verrous Redis (locks) pour garantir que même si un message est livré plusieurs fois (at-least-once delivery), il n'est traité qu'une seule fois.
|
|
122
|
+
- **Circuit Breaker** : Interrompt automatiquement la consommation si un seuil élevé d'erreurs est atteint, évitant les pannes en cascade.
|
|
123
|
+
- **Backoff Exponentiel** : Décale progressivement les tentatives de retry pour laisser le temps aux services défaillants de récupérer.
|
|
124
124
|
|
|
125
|
-
##
|
|
125
|
+
## Utilisation avec NestJS
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
L'intégration d'un post-processor dans une application NestJS implique la création d'un service qui étend soit `SinglePostProcessor` soit `BatchPostProcessor` et la gestion de son cycle de vie.
|
|
128
128
|
|
|
129
|
-
### 1.
|
|
129
|
+
### 1. Créer le Service Post-Processor
|
|
130
130
|
|
|
131
131
|
```typescript
|
|
132
132
|
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
@@ -188,17 +188,17 @@ export class UserAnalyticsPostProcessor extends SinglePostProcessor implements O
|
|
|
188
188
|
|
|
189
189
|
protected async processEvent(event: StreamEvent<any>, messageId: string): Promise<void> {
|
|
190
190
|
this.nestLogger.log(`Processing event ID: ${event.id}`);
|
|
191
|
-
//
|
|
191
|
+
// Implémentez la logique métier ici
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
### 2.
|
|
196
|
+
### 2. Enregistrer dans un Module
|
|
197
197
|
|
|
198
198
|
```typescript
|
|
199
199
|
import { Module } from '@nestjs/common';
|
|
200
200
|
import { UserAnalyticsPostProcessor } from './user-analytics.post-processor';
|
|
201
|
-
import { RedisModule } from './redis.module'; //
|
|
201
|
+
import { RedisModule } from './redis.module'; // Suppose que vous avez un module fournissant Redis
|
|
202
202
|
|
|
203
203
|
@Module({
|
|
204
204
|
imports: [RedisModule],
|
|
@@ -207,4 +207,4 @@ import { RedisModule } from './redis.module'; // Assume you have a module provid
|
|
|
207
207
|
export class AnalyticsModule {}
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
En s'accrochant à `OnModuleInit` et `OnModuleDestroy`, le cycle de vie de l'application NestJS démarrera automatiquement les boucles en arrière-plan lorsque l'application démarre et les arrêtera proprement lors de son arrêt.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volontariapp/post-processors",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.10-snap-d0fb360",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"provenance": true
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"test:int:watch": "INTEGRATION=true node --experimental-vm-modules $(yarn bin jest) --watch"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@volontariapp/database": "3.4.
|
|
41
|
-
"@volontariapp/health-check": "1.0.
|
|
42
|
-
"@volontariapp/logger": "0.2.
|
|
43
|
-
"@volontariapp/messaging": "2.10.
|
|
44
|
-
"@volontariapp/outbox": "0.9.
|
|
45
|
-
"@volontariapp/shared": "0.8.
|
|
40
|
+
"@volontariapp/database": "3.4.6-snap-d0fb360",
|
|
41
|
+
"@volontariapp/health-check": "1.0.6",
|
|
42
|
+
"@volontariapp/logger": "0.2.7",
|
|
43
|
+
"@volontariapp/messaging": "2.10.3-snap-d0fb360",
|
|
44
|
+
"@volontariapp/outbox": "0.9.43-snap-d0fb360",
|
|
45
|
+
"@volontariapp/shared": "0.8.1"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@nestjs/common": "^11.0.0",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"@nestjs/common": "^11.0.0",
|
|
54
54
|
"@types/jest": "^30.0.0",
|
|
55
55
|
"@types/node": "^24.0.0",
|
|
56
|
-
"@volontariapp/contracts": "4.3.
|
|
57
|
-
"@volontariapp/testing": "1.0.
|
|
56
|
+
"@volontariapp/contracts": "4.3.4-snap-d0fb360",
|
|
57
|
+
"@volontariapp/testing": "1.0.3",
|
|
58
58
|
"ioredis": "^5.3.7",
|
|
59
59
|
"jest": "^29.7.0",
|
|
60
60
|
"reflect-metadata": "^0.2.2",
|