Quando si parla di messaggi, intesi come messaggi su una coda, c’è una cosa molto importante da comprendere:
I messaggi sono sempre e solo one-way, fire & forget.
A prescindere dal pattern di alto livello che stiamo usando, sia esso pub/sub o request/response, il mittente parla con una coda, il destinatario parla a sua volta con una coda, ma mittente e destinatario non sanno nulla l’uno dell’altro.
Two Generals' Problem
Questa puntualizzazione è molto importante perché introduce il noto problema dei due generali. Che in soldoni ci dice che il mettente non ha nessun modo di sapere con certezza se il messaggio sia stato consegnato al destinatario. Non esiste un concetto di ACK da parte dell’infrastruttura, e se anche lo inventiamo, sarebbe a sua volta un messaggio che a sua volta potrebbe non arrivare.
Perché vi sto dicendo tutto ciò?
Perché mi capita spesso, troppo spesso, di vedere cose del tipo:
queue.Send( message );
locker.Lock( message.id );
locker.Lock crea e usa un manual reset event, a questo punto questo thread è a tutti gli effetti congelato. E da qualche altra parte:
var message = queue.Deque();
locker.Unlock( message.id );
O, forse peggio, cose come:
var message = new QueryCustomers()
{
Filter = ….
};
queue.Send( message );
locker.Lock( message.id );
Vengono quindi usati messaggi e una coda per leggere informazioni, a tutti gli effetti eseguire query. Oppure come nel primo caso vogliamo a tutti i costi metterci una coda ma non siamo disposti a ripensare il processo per essere totalmente asincrono, e ci inventiamo pastrocchi tecnologici per mimare un approccio procedurale.
Due ordini di problemi
Il problema dei due generali ci dice chiaro e tondo che potremmo aspettare a vita. Il destinatario potrebbe essere giù, o fallire nel processare il messaggio e spostarlo in una coda di errore, di fatto non rispondendo mai.
Il secondo problema, tipico dell’usare messaggi per leggere informazioni, è derivante dall’infrastruttura e dal concetto di quota. Come ci dicono chiaramente le 8 fallacies of distributed computing la latenza non è zero e la banda non è infinita, ergo i trasporti devono proteggersi dalle cazzate degli sviluppatori e impongono limiti, spesso molto stringenti, sulle dimensioni dei messaggi. Ne consegue che aspettarsi di poter ritornare i risultati di una query non è cosa buona e giusta.
Concludendo
Non usate request/response, e in generale una coda e messaggi, per leggere informazioni. Ci hanno dato HTTP, e tanti altri bei trasporti e protocolli per farci qualche cosa, usateli :)
Lo scopo di messaggi su una coda è altro: è inviare comandi e notificare variazioni di stato pubblicando eventi.