web-dev-qa-db-ja.com

コマンドの検証後エラーを処理する方法(DDD + CQRS)

たとえば、登録フォームを送信するときは、Domain ModelWriteModel in CQRS)が有効な状態であることをチェックインする必要があります(例、電子メールアドレスの構文、年齢など)。

次に、Commandを作成し、Command Busに送信します。

コマンドが何も返さないことを理解しています。

では、Command Busを超えたエラーをどのように処理しますか? (たとえば、1秒前に同じusername/emailで登録したユーザー)。

コマンドが失敗したことをどのようにして確認し、エラーをどのようにして確認しますか?

18
JorgeeFG

コマンドが何も返さないことを理解しています。

これは1つの見解ですが、完全に完全なものではありません。 HTTPでの書き込み(PUT、POST、DELETE)を検討してください。これらのメッセージはすべて、リソースが状態を変更することを要求するメッセージであり、しかもすべてが応答を返すという意味でコマンドです。

では、コマンドバスを超えてエラーをどのように処理するのでしょうか。 (たとえば、1秒前に同じユーザー名/メールで登録したユーザー)。

コマンドが失敗したことをどのようにして知り、エラーをどのようにして知るのですか?

したがって、コマンドハンドラーと直接通信している場合、返されたメッセージは、コマンドが受信されて処理されたことを確認するための完全に合理的な方法です。

バスなどのミドルウェアを使用していて、ターゲットと直接通信できない場合は、非同期メッセージングパターンを検討することをお勧めします-コマンドハンドラーにメッセージを送信する方法発信者?

1つのアイデアは、コマンドの結果をサブスクライブすることです。これは、ホープのエンタープライズ統合パターンのアイデアの一部を借りています。基本的な考え方は、クライアントは送信されたコマンドメッセージに精通しているため、コマンドメッセージの結果として発行されたすべての新しいメッセージをサブスクライブすることができるということです。コマンドハンドラーは、データをレコードブックに保存した後、変更が成功したことを通知するイベントを発行し、クライアントはそれらのイベントをサブスクライブします-メッセージ内のさまざまな識別子(原因ID、 相関ID など)。

代替アプローチはもう少し直接的です。 1つは、メッセージにコールバックを含めることです。コールバックは、メッセージが正常に処理された後にコマンドハンドラーによって呼び出すことができます。

非常によく似た代替策は、コマンドハンドラーが確認応答を書き込むためにコマンドメッセージのスペースを予約することです-クライアントはすでに問題のコマンドメッセージを持っているので、回路はすでに完成しています。 " promise "または " completable future"。 と考えてください。メッセージはコマンドハンドラに確認応答を書き込む場所を指示します。そうすることで、確認応答が利用可能であることをクライアント(カウントダウンラッチ)に通知します。

そしてもちろん、ミドルウェアを削除するという追加のオプションがあり、それは単純に正しいことを行うのを邪魔しているように思われます。

たとえば、1秒前に同じユーザー名/メールで登録したユーザー

ユーザー登録をべき等で処理している場合、これは必ずしもエラーではありません。応答が確認されるまでメッセージを繰り返すことは、少なくとも1回の配信を保証する一般的な方法です。

4
VoiceOfUnreason

たとえば、登録フォームを送信するときは、ドメインモデル(CQRSのWriteModel)で、それが有効な状態(メールアドレスの構文、年齢など)であることを確認する必要があります。

検証には多くの種類があります。電子メールアドレスの構文と経過時間の形式を確認するときの検証は、コマンドが実行できる検証の一種です。これは実際にはドメインの問題ではありません。一部のドメインの専門家がそれらの仕様を教えてくれるので、そのように見えるかもしれませんが、コマンドの作成でこの種の検証を行う必要があります。実際、一般的な考え方は、コマンドを作成してBUSに送信した後でアクションを実行するのがより複雑になるため、できるだけ早く検証を行うことです。

では、コマンドバスを超えてエラーをどのように処理するのでしょうか。 (たとえば、1秒前に同じユーザー名/メールで登録したユーザー)。

この種の検証は、CQRSの最初からCQRSコミュニティで多く議論されています。どこでやるの?それは非常に議論されています。私は個人的に次のアプローチを使用します。コマンドがBUSに送信される前に、ユーザー名/メールを集中管理された方法で取得するようにマークします(つまり、ユーザー名/メールに対する一意のインデックス制約)。その後、コマンドを送信します。欠点は、コマンドが失敗した場合、短期間ユーザー名が取得されて使用されないことです。これは私のビジネスにとっては許容できるものであり、あなたのビジネスにとってはありそうなことです。

コマンドが失敗したことをどのようにして知り、エラーをどのようにして知るのですか?

ドメインが不変であるために非同期コマンドがAggregateによって拒否された場合は、何らかの方法でコマンドを発行者に通知する(つまり、コマンドが失敗したことを説明する電子メールを送信する)補正コマンドを発行して、いくつかの対策を講じる必要があります。

重複メールの問題は、そのメールアドレスが別の人のものであるため、メールを送信できないことです。そのため、コマンドをバスに送信する前に確認します。

2

検証はデコレータで実行する必要があります。次に、検証が必要なコマンドをそのように装飾できます。

検証は、コマンドでvoidを返す場合は例外で処理できるため、返されたタスク結果を含む同期または非同期呼び出しでそれらを取得できます。

別の可能性は、検証を検証結果を返す「クエリ」の一種と考えることです。検証クエリを実行し、渡された場合はコマンドを実行します。これは、デコレータアプローチの代替手段になります。

1
Jon Raynor