CQRS e microservizi: passaggio di informazioni da un servizio a un altro

2

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?
posta Peter 28.05.2018 - 15:44
fonte

1 risposta

6

We're building two microservices that use CQRS and Event Sourcing: an Order Service and an Inventory Service. When an order is made, the inventory of that item must be decreased by the amount ordered. An order can also be canceled. In that case, the inventory must be increased again.

Potresti farti inciampare perché stai confondendo la manipolazione dell'ordine con la prenotazione dell'inventario.

Suggerimento: la creazione di un ordine non esaurisce il tuo magazzino; prodotto di spedizione esaurisce il brodo.

A volte i pattern non si adattano perché stanno cercando di dirti che il modello è rotto.

Send a message with only the OrderId but have the Inventory Service listen to all necessary messages of the Order Service and build its own read model of the orders.

Voglio definirlo esplicitamente come una cattiva idea: il servizio di inventario non dovrebbe cercare di costruire il proprio modello di ordini letti; che collega il servizio di inventario ai componenti interni del modello di ordine e significa che non è possibile modificare facilmente il modello di ordine senza anche ridistribuire il servizio di inventario.

Ma ... è perfettamente ragionevole che il servizio di inventario abbia il proprio proprio modello per "inventario riservato" che costruisce a causa dei messaggi che riceve dal servizio dell'ordine.

In altre parole, durante la cancellazione il servizio di inventario non si cura di quali siano gli articoli dell'ordine, si preoccupa solo di quale stock è stato riservato per quell'ordine. Può guardare nel suo negozio per quello ....

How do I tackle the issue where an Event Handler needs more information?

Una cosa da tenere a mente: quando un evento raggiunge un gestore di eventi, l'evento è stantio .

Se il Servizio di inventario riceve un evento e necessita di informazioni aggiuntive per agire su di esso, interroga l'autorità per le informazioni di cui ha bisogno. Pertanto, se il servizio di inventario deve conoscere lo stato dell'ordine in quanto l'ordine è stato annullato, invia una query al servizio ordini chiedendo le informazioni di cui ha bisogno.

Nota la separazione: stabilisci un contratto API che consente al servizio di inventario di chiedere ciò di cui ha bisogno e uno schema per i messaggi scambiati. I due servizi possono cambiare in modo indipendente in qualsiasi modo che rispetti tale API.

Quindi potresti immaginare uno scambio in cui il servizio di inventario riceve una sottile notifica che un ordine è stato annullato e quindi interroga il servizio ordini per ottenere una rappresentazione più completa dell'ordine in quel momento.

Quella query non deve necessariamente essere sincrono - il risultato della query è solo un altro messaggio di input per il servizio di inventario.

Does a microservices architecture mean I will need lots of read models (aka endpoints) per client?

Scrivi solo i database non sono molto interessanti, quindi avrai bisogno di endpoint che ti consentano di recuperare i dati. Se fai attenzione ai tuoi progetti di API, non dovrai necessariamente bisogno di più modelli di lettura di quanto faresti in un monolite. Tuttavia, a volte è necessario supportare più di un modello di lettura per una determinata funzionalità, in modo che i client legacy e quelli aggiornati possano entrambi accedere alle informazioni necessarie.

    
risposta data 28.05.2018 - 18:55
fonte

Leggi altre domande sui tag