Stream guidance

If it successfully sent, but timed out waiting for a response it also might have worked. Either way, what happened is indeterminate, and the user will have to check things before they continue.

You can use event stores idempotency to handle many of these scenarios.

I could add some limited retries in case of a non-timeout transient fault. For now I’ll just let the user retry manually, and if it keeps happening they will call the admin. :slight_smile:

Just as note (subtle difference)

I normally teach there is no such thing as a one way command eg transferfunds in this case it’s the client raising an event fundstransferrequested

I don’t consider these as one-way commands. The client absolutely expects a response (and receives Task as a marker). Commands this way are just very asynchronous. All the same things can happen with a “synchronous” command (timeout saving events (might have saved), crash during send).

I see your point about retrying the command though, because I wouldn’t want to do something like run a credit card twice by sending the same command with a different message id where the first might have run. I suppose the client app could have some responsibility in this.

And actually, opcon will still take care of not charging the card twice, but Event Store’s idempotency could prevent it from getting that far.

I’ve ultimately decided that I have overcomplicated things for my future self. I’m just gonna post the commands to an MVC action like I have already done to death.

My one wrinkle is that I still want to save the commands in the event store for regression testing. If denormalizers subscribe to all events, these will also be encountered. Is there a way to exclude a stream from a subscribe to all?

“I’ve ultimately decided that I have overcomplicated things for my future self.”

#awesome

Make your own projection.

function isCommand(e) {

// when you persist your commands use metadata to identify them

// then check for it here

}

fromAll()

.when({

$any: function(s, e) {

if (e.Type.startsWith("$")) return;

if (isCommand(e)) return;

linkTo(“all-events”, e);

}

});

Someone else should weigh in on this, but I don’t believe you get perfect ordering here like you do on the $all stream. So just make sure your subscribers don’t care :slight_smile:

Sure just filter them or make a custom stream

While I was cutting things out, I figured I would see how far I could go without projections. Because now I wouldn’t need them.

Filtering out commands is a solvable problem, but annoying since right now my event and command envelopes don’t share a common interface (metadata classes different too). Best case, I put a marker interface on metadata, deserialize to that, then do an ‘as’ cast to the event metadata (which tells me the payload type). And all that is only necessary because I want to log commands.

Is there a more elegant solution?

Just treat it as json?

With JObject? And define metadata key constants? Meh.

Key constants? Your metadata is just json not types. If you look at it as types there will be many problems later

Good to know. Like what though?

Versioning for one.

Secondly it’s a bit of a jump to assume that all consumers of your data forever will use a for type system. Focus on the schema of the json first then maybe map to types if you want.

I haven’t been including type information in the metadata. It has been just json, but with the subtext that when I pull from a command stream, I map it to the CommandMetadata class vs the EventMetadata class.

Looks like resolved event gives me original stream id, and that’s all I need to filter out the command stream. Sorry for a redundant question.

Although now I am curious about using metadata classes. I figured I would use them for the obvious infrastructure concerns (destination id, version, etc) and later add a dictionary to it for one-off concerns.

Json is a dictionary :slight_smile:

I need more structure in my life! And I’m taking it out on the metadata.