Tag: event-driven, architecture, pub-sub, message-broker, async, decoupling
Livello: intermedio
TL;DR: Architettura software in cui il flusso del programma è determinato da eventi generati, rilevati e consumati in modo asincrono, garantendo elevato disaccoppiamento e scalabilità.
Producer o Publisher genera ed emette eventi senza avere conoscenza di chi li riceverà.
Consumer o Subscriber si iscrive per ascoltare specifici eventi ed eseguire logica di business in risposta.
Message Broker o Event Bus è l'infrastruttura middleware (es. Kafka, RabbitMQ, EventBridge) che instrada gli eventi.
Disaccoppiamento forte: i servizi non comunicano direttamente tra loro, facilitando manutenzione e deploy indipendenti.
Elaborazione asincrona: i producer non restano in attesa (non bloccanti) della risposta dei consumer.
Eventual Consistency: la coerenza dei dati tra microservizi non è immediata ma viene raggiunta nel tempo.
Event Sourcing: lo stato di un'entità non è salvato come record singolo, ma calcolato riproducendo una sequenza immutabile di eventi passati.
Choreography vs Orchestration: in architetture a microservizi, l'event-driven favorisce la coreografia (ogni servizio agisce autonomamente all'evento) rispetto a un orchestratore centrale.
Q: Qual è la differenza principale tra un'architettura Request-Response e una Event-Driven?R: Nella Request-Response i servizi sono accoppiati temporalmente e funzionalmente, se il destinatario è down la chiamata fallisce. Nell'Event-Driven il producer emette l'evento e prosegue; il consumer lo processerà non appena disponibile.
Q: Come gestisci il caso in cui un consumer non riesca a elaborare un evento per un errore temporaneo o permanente?R: Configuro policy di retry con backoff esponenziale. Se l'errore persiste dopo i tentativi massimi, indirizzo l'evento verso una Dead Letter Queue (DLQ) per analisi manuale o replay successivo.
Q: Come affronti il problema della ricezione duplicata degli eventi?R: Implemento i consumer in modo che siano idempotenti, utilizzando chiavi univoche (come un correlation ID) per scartare i messaggi già elaborati correttamente o effettuando upsert sul database.
Mancanza di tracciabilità distribuita, rendendo complesso il debug (fondamentale usare un correlation ID propagato tra i servizi).
Assumere che l'ordine di arrivo degli eventi sia sempre garantito (dipende dal broker e dalle partizioni usate).
Progettare eventi troppo granulari o troppo pesanti, intasando la rete o violando la privacy dei dati nel payload.
Rischio di "Event Storming", dove un evento scatena una reazione a catena incontrollabile tra i vari servizi (loop infiniti).
```import { EventEmitter } from 'events';
class OrderService extends EventEmitter {
createOrder(orderData: any) {
// Logica di creazione ordine...
const order = { id: 123, status: 'CREATED', ...orderData };
// Emette l'evento per gli altri sottosistemi
this.emit('OrderCreated', order);
return order;
}
}
const orderService = new OrderService();
// Un ipotetico Consumer per le notifiche
orderService.on('OrderCreated', (order) => {
console.log([Notification Service] Invio email per ordine: ${order.id});
});
orderService.createOrder({ amount: 150 });
```
[ ] Pattern CQRS in combinazione con Event Sourcing.
[ ] Implementazione e gestione del pattern Saga (Coreografia) tramite eventi.
[ ] Differenze architetturali tra Kafka (Log-based) e RabbitMQ (Queue-based).