Warm tip: This article is reproduced from serverfault.com, please click

MassTransit: Queing consumption of different messages for related data

发布于 2020-11-29 15:30:00

Setup

I'm using ASPNET Core with EFCore.

I've setup MassTransit to help in the replication of Users and Tokens between services.

Each User has multiple Tokens and they are connected by Token.UserId foreign key.

The Issue

When a new User is created, two things happen:

  • User and fresh Token are stored in the database
  • UserCreated and TokenCreated are sent to the message bus simulatenously

In effect, Token (since it's smaller) is processed before User and an error pops saying that User of given Id defined in Token.UserId doesn't exist in table Users - which is true, because User is created asynchronously along with Token.

I've found a few solutions, like removing foreign key constraints or implementing a delay in Consume method - both of which seemed to be lazy solutions that'll eventually come back to me.

Is there a way to perhaps put both events on the same queue and execute them in order they are added to it or should I just include the initial Token in UserCreated?

Questioner
JCode
Viewed
0
Chris Patterson 2020-11-29 23:58:17

When it comes to message contract design, particularly when producing events...

Events should be self-contained

Each event should be a complete representation of a specific event. This means that an event should not reference other data sources, should not include foreign keys, and should not require callbacks to a backing service to be able to do something in response to the event.

In your scenario, you may want to either include enough user information in the TokenCreated event such that a new user could be added based on the data in that event, or create a third event that includes both data sets – perhaps a UserTokenCreated. That third event would be produced when both a new user and new token are created at the same time.

Another option would be to use a saga to combine the two events, but that seems more complexity than you need.

You could also use the broker's delayed message feature to reschedule delivery of the message in the future by some delay instead of simply blocking a consumer slot by using Task.Delay() as you seem to be doing now.