Stiamo costruendo due microservizi che utilizzano CQRS e Event Sourcing: un servizio ordini e un servizio di inventario. Quando viene effettuato un ordine, l'inventario di quell'articolo deve essere diminuito dell'importo ordinato. Un ordine può anche essere cancellato. In tal caso, l'inventario deve essere aumentato nuovamente.
Quindi nel Servizio ordini memorizziamo un evento OrderCreated
che contiene i dettagli necessari per il servizio di inventario: un elenco di istanze Item
con i relativi ID e importi. Codice di esempio:
public class OrderCreated
{
public int OrderId { get;set; }
public IList<Item> Items { get; set; }
}
public class Item
{
public int Id { get; set; }
public int Amount { get; set; }
}
Questo evento viene anche inviato al servizio di inventario (potrebbe essere associato a un contratto condiviso), pertanto il servizio di inventario può ridurre lo stock per gli articoli.
Quando un ordine viene annullato, archiviamo un evento OrderCanceled
. Per il servizio ordini, questo deve solo contenere un OrderId
, ad esempio:
public class OrderCanceled
{
public int OrderId { get;set; }
}
Ma come possiamo inviare gli articoli al servizio di inventario?
Opzione 1
Aggiungi gli articoli all'evento OrderCanceled
:
public class OrderCanceled
{
public int OrderId { get;set; }
public IList<Item> Items { get; set; }
}
Questo ci sembra strano, perché quando si ri-applica l'evento (cioè l'idratazione), questo non ha alcuno scopo.
Opzione 2
Crea un gestore eventi per l'evento OrderCanceled
, che recupera l'aggregato e accede agli elementi, ad esempio (codice non reale):
public class MyEventHandler : IEventHandler<OrderCanceled>
{
public void Handle(OrderCanceled e)
{
var order = _repository.Get(e.OrderId);
var message = new OrderCanceledMessage
{
OrderId = e.OrderId,
Items = order.Items.Select(x => new ItemMessage(...))
};
_messageSender.Send(message);
}
}
La cosa strana qui è che stiamo recuperando l'istanza Order
, anche se l'abbiamo già recuperata in precedenza nel nostro gestore di comandi (ad esempio, quando l'utente ha annullato l'ordine, è stato inviato al sistema un comando). Quindi abbiamo recuperato il nostro aggregato due volte.
Opzione 3
Uguale all'opzione 2, ma invece di recuperare Order
nel gestore eventi, lasciamo che il gestore eventi chiami il modello letto per recuperare gli elementi.
Tuttavia, nella maggior parte degli articoli che ho letto, si consiglia di non chiamare dal lato comando il lato query (anche se spesso con poche argomentazioni).
Opzione 4
Invia un messaggio con solo OrderId
ma fai in modo che il Servizio di inventario ascolti tutti i messaggi necessari del Servizio ordini e costruisca il proprio modello di lettura degli ordini.
Questo significa che avremmo effettivamente dei componenti per creare un modello di lettura per il loro uso, invece di leggere i modelli per gli altri. Nell'esempio precedente, il servizio di inventario crea un modello degli ordini con i relativi articoli.
Il vantaggio sembra qui che puoi costruire un modello di lettura esclusivamente per il tuo uso personale. In una situazione di microservizi, temiamo che un componente possa dover costruire troppi modelli di lettura diversi per tutti i diversi microservizi.
Uno svantaggio potrebbe essere che le modifiche / aggiunte di eventi nel Servizio ordini richiederebbero modifiche nella generazione del modello di lettura del Servizio di inventario.
Quindi cosa sto chiedendo qui?
- Come posso affrontare il problema in cui un gestore di eventi ha bisogno di più informazioni?
- L'architettura di un microservizio significa che avrò bisogno di molti modelli di lettura (noti anche come endpoint) per client?