Do the events that occur when a command has executed in a CQRS-System have the same id as the Command, so that they can be associated to the command.
I´m currently implementing Saga´s in my CQRS-System and as far as i understand the concept of sagas is that they handle specific events to then define and execute commands to complete the process that is represented by the Saga.
My problem now is that how does the Saga know that the event that it is handling is the event it is waiting for.
Should i store the Id of the command that gets passed to the CommandBus in the Saga to wait for an event with the same Id? What if the execution of the command results in many diffrent events, do they all have the same Id?
For sagas, there has to be some correlating key on the constituent messages. Sometimes this can be a natural business domain key, such as OrderId. Other times a globally unique key is more appropriate such as a Guid. This key correlates messages related to a single task implemented by the saga.
In your case it seems that this correlating ID is the ID of the command which starts the saga.
Should i store the Id of the command that gets passed to the
CommandBus in the Saga to wait for an event with the same Id?
Yes. If you can assert that this ID is unique and fully identifies the task which the saga implements then this should be the correlating ID of the saga.
What if the execution of the command results in many diffrent events,
do they all have the same Id?
They all share a correlation ID, but I don't think of it as an ID for the event. The event may have an individual ID on its own, but for the saga to function, it has to have a correlation ID.
I agree with eulerfx and would like to add a point:
If the Saga is releated to a specific Aggregate the Aggregate's Id would be sufficient.
Command: CreateCustomer { CustomerId = New Guid }
- Creates Customer Aggregate with CustomerId
- Emits Event CustomerCreated { CustomerId = Customer.CustomerId }
Command: BlackListCustomer { CustomerId = Customer.CustomerId }
- Blacklists Customer
- Emits Event CustomerBlacklisted { CustomerId = Customer.CustomerId }
Saga: CustomerLifecycle
- Listens to Event CustomerCreated
- Stores created customer's CustomerId
- Listens to Event BlacklistCustomer and only acts if CustomerIds match
Related
In Mixpanel, Users can have multiple Distinct IDs that can be merged under 1 identity. The User is identified with a default Distinct ID, which we’ve noticed is the first one created, not the most recent or one that we would explicitly prefer as the default.
Is it possible to set a default/primary Distinct ID?
Also related, once a user signs up, we are using email address as the Distinct ID. If the user changes their email address, would we need to create an alias (we have Identity Merge enabled, FYI), or update the Distinct ID with their new email?
I did read on this support article titled "Moving to Identity Merge" that:
You can no longer control the canonical id for users in Mixpanel
The ID merge system will now determine which distinct_id is used as the canonical id for a user in Mixpanel. Any merged id can be used to query for information about a user with our APIs, but the results of the query may return a with different canonical distinct_id value than the one used in the query.
I had a similar issue, we use a server-side implementation but this should apply to client side as well, my flow was:
send some anonymous track() events with anon_id & distinct_id uuidv4. Let's say the anon_id is: abc-123
authenticate user (now we have access to user_id)
call identify() with user_id and anon_id
send some track() events with our internal user_id as the distinct_id. For example the user_id is: 1001
We noticed that the default mixpanel canonical distinct_id would always be abc-123, not 1001 like we wanted.
After playing around with the mixpanel API I have discovered that if you create the user profile before identifying, the problem seems to be fixed.
mixpanel.people.set(distinct_id, props);
mixpanel.identify(); // our api is identify(user_id, anon_id)
Going through he flow again, the canonical distinct_id is now 1001 instead of abc-123. I believe this fixes it because creating a profile for the user sets the canonical distinct_id (no source on this though).
To be clear, the flow afterwards is:
send some anonymous track() events with anon_id & distinct_id uuidv4: abc-123
authenticate user
call mixpanel.people.set(distinct_id, props) // distinct_id = user_id
call identify() with user_id and anon_id
send some track() events with our internal user_id: 1001
Then 1001 should be the default canonical distinct_id instead of abc-123.
I am looking into event sourcing and I have a few thoughts that I need to get my head round.
Take for example an online shop -
The customer adds an item to the basket and saves their order.
The command handler could create an order on the customer aggregate root and add an OrderCreated event which contained the customer id, order id, item id, quantity and unit price. All pretty straight forward but what if the aggregate needed to check to see if that item was on special offer?
If this was for example a basket service would it subscribe to events from the catalog service and store it's own projections of the catalog service which it could then use, so then the basket service would comprise an event store and also some form of projection of the catalog service?
Or if in the example I've just described, if the basket and catalog functionality were part of the same application and they only held event data, then when a customer creates an order the handler would pull all ordered items from the event store via a repository, apply all events to them and then return them to the handler in order to check if the item was on special offer.
what if the aggregate needed to check to see if that item was on special offer?
It needs to execute a query to get the information it needs.
From the aggregate point of view those data are external, so it (or the handler sending the command to it) needs a query to access that information.
How the query work is up to you (there are pros and cons for each way), the query handler can:
Call a repository that loads an aggregate and check for the special offer (you can also think to have event sourcing in just one part of your system and having this part using another way to store dara, or not)
Make a remote call to the Catalog Service API to check for the special offer
Do a query to a local db, that is populated reading events emitted by the catalog service and stored "locally" to the basket service
There is a possibility to call an on-demand workflow from CRM advanced find screen.
To initiate a workflow, user needs to select records first.
How to pass the selected data to the custom workflow?
e.g.
When you run Workflow with trigger such as Create or Record or Update of Record or Record assigned or so on i.e automatic trigger, Workflow Activity will have Input Parameter as Target i.e context of Record from which workflow is triggered. In Target you can find info such as record Id, Fields and so on.
But when you run OnDemand workflow, Workflow Activity will not contain Input parameter and hence details such as field and so on from which record it is fired will not be available.
You will only receive few info such as Record Id, Record Logical Name but not field detials.
You will need to Retreive Record with Given Record ID and Record Logical Name
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
Entity abc= service.Retrieve(context.PrimaryEntityName, context.PrimaryEntityId, new ColumnSet("colum1", "field2", "field3", "field4"));
Here is the link which explains all in Details
Theoretically when using event sourcing you don't store "state" but events. But I saw in many implementations that you store snapshots of state in a column in a format like JSON or just a BLOB. For example:
Using an RDBMS as event sourcing storage
The events table has Data column which stores entire object. To me, it's like storing state for that given time when some event occurred.
Also this picture(taken from Streamstone):
It has Data column with a serialized state. So it stores state too but inside an Event?
So how to replay from the initial state then, If I can simply pick some event and access Data to get the state directly.
What exactly is stored inside Data, is it a state of the entire object or it's serialized event?
Let's say I have a person object (in C#)
public class Person
{
public string Name { get; set }
public int Age { get; set; }
}
What should my event store when I create a person or change properties like name or age.
When I create a Person I most likely will send something like PersonCreatedEvent with the initial state, so the entire object.
But what if I change Name or Age should they be 2 separate events or just 1? PersonChangedEvent or PersonChangedAgeEvent and PersonChangedNameEvent?
What should be stored in the event in this case?
What exactly is stored inside Data, is it a state of the entire object or it's serialized event?
That will usually be a serialized representation of the event.
One way of thinking about it: a stream of events is analogous to a stream of patch documents. Current state is calculated by starting from some known default state and then applying each patch in turn -- aka a "fold". Previous states can be recovered by choosing a point somewhere in the stream, and applying the patches up to that point.
The semantics of events, unlike patches, tends to be domain specific. So Checked-In, Checked-Out rather than Patched, Patched.
We normally keep the events compact - you won't normally record state that hasn't changed.
Within your domain specific event language, the semantics of a field in an event may be "replace" -- for example, when recording a change of a Name, we probably just store the entire new name. In other cases, it may make sense to "aggregate" instead -- with something like an account balance, you might record credits and debits leaving the balance to be derived, or you might update the total balance (like a gauge).
In most mature domains (banking, accounting), the domain language has semantics for recording changes, rather than levels. We write new entries into the ledger, we write new entries into the checkbook register, we read completed and pending transactions in our account statement.
But what if I change Name or Age should they be 2 separate events or just 1? PersonChangedEvent or PersonChangedAgeEvent and PersonChangedNameEvent?
It depends.
There's nothing wrong with having more than one event produced by a transaction.
There's nothing wrong with having a single event schema, that can be re-used in a number of ways.
There's nothing wrong with having more than one kind of event that changes the same field(s). NameLegallyChanged and SpellingErrorCorrected may be an interesting distinction to the business.
Many of the same concerns that motivate task based UIs apply to the design of your event schema.
It still seems to me like PersonChangedEvent will contain all person properties that can change. Even if they didn't change
In messaging (and event design takes a lot of lessons from message design), we often design our schema with optional fields. So the event schema can be super flexible, while any individual representation of an event would be compact (limited to only the information of interest).
To answer your question, an event that is stored should be the event data only. Not the objects state.
When you need to work on your Entity, you read up all the events and apply them to get the latest state every time. So events should be stored with the events data only. (ofc together with AggregateId, Version etc)
The "Objects State" will be the computation of all events, but if you have an Eventlistener that listens to all your published events you can populates a separate ReadModel for you. To query against and use as read only from a users perspective.
Hope it helps!
Updated answer to updated question:
Really depends on your model, if you do the update at the same time Age and Name, yes the new age and name values should be stored in a new event.
The event should only contain this data "name and age with aggregateId, version etc"
The event listener will listen specifically on each event (created, updated etc), find the aggregates read model that you have stored and only update these 2 properties (in this example).
For createevent you create the object for the read model.
I've a trigger that detects a change on a field PHONE_EXT and POSTs an EVENT. I would like to post the Phone_ID with the event in order to use this ID in the client. Is this possible? How?
CREATE TRIGGER tr2 FOR employee
ACTIVE AFTER UPDATE POSITION 0
AS
BEGIN
IF (new.PHONE_EXT <> old.PHONE_EXT) THEN
POST_EVENT 'phone_ext_changed'; <-- I would like to pass a string parameter with record ID
END
AFAIK, you cannot pass parameters, but you can get what you want with one of this ideas:
If in your client you're interested in events over specific records, you can append the ID of the changing record and post that event. The clients register the events in which are interested using the specific ID's of interest. See example 1.
if your front-end are interested in all changes but you want to know which particular records changed, you can "flag" the records as "recently changed" (using another field on the same record, or a detail table, for example). Upon client notification and action it reverts or clears the flag. This approach may be powered, for example, using auxiliary tables to track missing records from specific clients, it depends on your needs.
Example 1
begin
if (new.phone_ext <> old.phone_ext) then
post_event 'phone_ext_changed_'||new.ID;
end
Example 2
begin
if (new.phone_ext <> old.phone_ext) then
begin
new.recent_ext_change = 1;
/* or maybe */
new.last_ext_change = cast('now' as DateTime);
/* or maybe */
insert into changed_phone_ext values (gen_id(some_generator, 1), New.ID, 'now');
/* finally, post the event */
post_event 'phone_ext_changed_';
end
end
I'm using both with success in different applications/situations.
You can use it as follows:
Set a context variable in the trigger and place the desired information in it.
Ex.:
Create trigger evento_ai0 for evento
active after insert position 0
AS
BEGIN
Post_Event 'Evento_inserido';
"Creating the context variavble"
rdb$set_context('USER_SESSION', 'REGISTRO' , 'Registro inserido: '||new.eve_id);
END
To capture the saved information use:
Select rdb$get_context('USER_SESSION', 'REGISTRO') from rdb$database;
This is not possible. The event is a name only, if you add ids or other qualifiers, it simply becomes a different event because it has a different name. When subscribing to events, you can only subscribe by name, you can't use wildcards, and it is not possible to include parameters.
Events are for simple and cheap notification, and Firebird can even coalesce multiple 'posts' of the same event into a single notification to a client, so parameters or values are not supported.
The basic idea is that a client subscribe to events, and then determines what changed and what it needs to react to. You can 'help' the client by - for example - populating a support table that is cheap to query.
Also consider reading the article "The Power of Firebird Events", it is a bit old, but a lot of it still applies as Firebird events haven't changed much.