Come gestire gli errori di post-convalida in comando (DDD + CQRS)

14

Ad esempio, quando si invia un modulo di registrazione, è necessario controllare Domain Model ( WriteModel in CQRS ) che sia in uno stato valido (ad esempio, sintassi dell'indirizzo e-mail, età, ecc.).

Quindi crei un Command e invialo a Command Bus .

Capisco che i comandi non dovrebbero restituire nulla.

Quindi come gestisci un errore oltre Command Bus ? (Ad esempio, un utente si è registrato 1 secondo prima con lo stesso username/email ).

Come sai che il comando è fallito e come fai a sapere l'errore?

    
posta JorgeeFG 13.03.2017 - 15:44
fonte

3 risposte

2

I understand that Commands should not return anything.

Questa è una visione, ma non è interamente scolpita nella pietra. Prendi in considerazione le scritture (PUT, POST, DELETE) in HTTP: tutti questi messaggi sono comandi, nel senso che sono messaggi con richiesta di modifica dello stato della risorsa e tuttavia restituiscono tutte le risposte.

So how do you handle an error beyond Command Bus? (For example, a user registered 1 second before with the same username/email).

How do you know that command failed, and how do you know the error?

Quindi, nel caso in cui comunichi direttamente con il gestore comandi, un messaggio restituito è un modo perfettamente ragionevole per riconoscere che il comando è stato ricevuto ed elaborato.

Se stai usando un pezzo di middleware, come un bus, che ti impedisce di comunicare direttamente con il target, allora ti suggerisco di guardare a schemi di messaggistica asincroni - come fai a mandare un messaggio al gestore di comandi torna al chiamante?

Un'idea è iscriversi al risultato del comando; questo prende a prestito alcune delle idee contenute negli Enterprise Integration Pattern di Hohpe. L'idea di base è che, poiché il client ha familiarità con il messaggio di comando inviato, è ben posizionato per sottoscrivere qualsiasi nuovo messaggio pubblicato come conseguenza del messaggio di comando. Il gestore di comandi, dopo aver salvato i dati nel registro, pubblica eventi che annunciano che il cambiamento ha avuto esito positivo e il cliente si iscrive a tali eventi, riconoscendo gli eventi corretti considerando la coincidenza di vari identificatori nel messaggio (ID di causalità, ID di correlazione e così via).

Gli approcci alternativi sono un po 'più diretti. Uno sarebbe quello di includere nel messaggio un callback, che può essere richiamato dal gestore comandi dopo che il messaggio è stato gestito con successo.

Un'alternativa molto simile è quella di riservare spazio nel messaggio di comando affinché il gestore comandi scriva il riconoscimento - poiché il client ha già il messaggio di comando in questione, il circuito è già completo. Pensa " promessa " o " completabile futuro". Il messaggio indica al gestore comandi dove scrivere il riconoscimento; facendo così segnali al client (conto alla rovescia) che il riconoscimento è disponibile.

E, naturalmente, hai l'opzione aggiuntiva di rimuovere il middleware che sembra stia ostacolando il modo di fare la cosa giusta semplicemente.

For example, a user registered 1 second before with the same username/email

Se gestisci la registrazione dell'utente in modo idonea, non sarebbe necessariamente un errore - i messaggi che si ripetono finché non viene osservata una risposta è un modo comune per garantire almeno una volta il recapito.

    
risposta data 14.03.2017 - 07:25
fonte
1

For example, when you submit a Register form, you have to check in the Domain Model (WriteModel in CQRS) that it is in a valid state (example, email address syntax, age, etc)

Esistono molti tipi di convalida. La convalida quando si controlla la sintassi dell'indirizzo e-mail e il formato dell'età è un tipo di convalida che un comando può eseguire. Questa non è una preoccupazione per il dominio. Potrebbe sembrare così perché alcuni esperti di dominio ti direbbero queste specifiche ma dovresti fare questo tipo di convalida nella creazione del comando. In effetti, l'idea generale è di fare la convalida il più presto possibile perché dopo che un comando è stato creato e inviato a un BUS è più complicato intraprendere azioni.

So how do you handle an error beyond Command Bus? (For example, a user registered 1 second before with the same username/email).

Questo tipo di convalida è discusso molto nella comunità CQRS, dall'inizio di CQRS. Dove si fa? È molto dibattuto. Io personalmente uso il seguente approccio: Prima che il comando venga inviato al BUS, contrassegno il nome utente / email come preso in maniera centralizzata (cioè un vincolo di indice univoco su nome utente / email). Dopo di che invio il comando. Lo svantaggio è che, se il comando fallisce, per un breve periodo di tempo il nome utente viene preso e non utilizzato; questo è accettabile per la mia attività, probabile per la tua attività.

How do you know that command failed, and how do you know the error?

Se un comando asincrono viene respinto da Aggregate a causa di un invariante di dominio, allora è necessario prendere alcune misure emettendo un comando compensativo che in qualche modo notifica l'emittente del comando (ad esempio, invia un'email di spiegazione che il comando non è riuscito).

Il problema con l'email duplicata è che non è possibile inviare un messaggio di posta elettronica perché quell'indirizzo email appartiene a un'altra persona, per questo motivo lo controllo prima di inviare il comando al bus.

    
risposta data 13.03.2017 - 16:48
fonte
0

La convalida deve essere eseguita in un decoratore. Quindi qualsiasi comando che richiede la convalida può essere decorato come tale.

Le convalide possono essere gestite con eccezioni se la restituzione è annullata con il comando in modo che possano essere raccolte con chiamate di sincronizzazione o asincrone con il risultato dell'attività restituita.

Un'altra possibilità è pensare alla convalida come a un tipo di "query" che restituirebbe un risultato di convalida. Esegui la query di convalida, quindi, se passata, esegui il comando. Questa sarebbe un'alternativa all'approccio decoratore.

    
risposta data 13.03.2017 - 18:21
fonte