Commands & Events: What’s the difference?

One of the building blocks of messaging is, you guessed it, messages! But there are different kinds of messages: Commands and Events. So what’s the difference? Well, they have very distinct purposes, usage, naming, ownership, and more!

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything in this post.

Commands

The purpose of commands is the intent to invoke behavior. When you want something to happen within your system, you send a command. There is some type of capability your service provides and you need a way to expose that. That’s done through a command.

I didn’t mention CRUD. While you can expose Create, Update, and Delete operations through commands, I’m more referring to specific behaviors you want to invoke within your service. Let CRUD just be CRUD.

Commands have two parts. The first is the actual message (the command), which is the request and intent to invoke the behavior. The second is consumer/handler for that command which is performing and executing the behavior requested.

Commands have only a single consumer/handler that resides in the same logical boundary that defines and owns the schema and definition command.

Commands can be sent from many different logical boundaries. There can be many different senders.

To illustrate this, the diagram below has many different senders, which can be different logical boundaries. The command (message) is being sent to a queue to decouple the sender and consumer.

Commands & Events: What's the difference?

A single consumer/handler, that owns the command, will receive/pull the message from the queue.

When processing the message, it may interact with its database, as an example.

Commands & Events: What's the difference?

As mentioned, there can be many senders, so we could have a completely different logical boundary also sending the same command to the queue, which will be processed the same way by the consumer/handler.

Lastly, naming is important. Since a command is the intent to invoke behavior, you want to represent it by a verb and often a noun. Examples are PlaceOrder, ReceiveShipment, AdjustInventory, and InvoiceCustomer. Again, notice I’m not calling these commands CreateOrder, UpdateProduct, etc. These are specific behaviors that are related to actual business concepts within a domain.

Events

Events are about telling other parts of your system about the fact that something occurred within a service boundary. Something happened. Generally, an event can be the result of the completion of a command.

Events have two parts. The first is the actual message (the event), which is the notification that something occurred. The second is the consumer/handler for that event which is going to react and execute something based on that event occurring.

There is only one logical boundary that owns the schema and publishes an event.

Event consumers can live within many different logical boundaries. There may not be a consumer for an event at all. Meaning there can be zero or many different consumers.

To illustrate, the single publisher that owns the event will create and publish it to a Topic on a Message Broker.

Commands & Events: What's the difference?

That event will then be received by both consumers. Each consumer will receive a copy of the event and be able to execute independently in isolation from each other. This means that if one consumer fails, it will not affect the other.

Commands & Events: What's the difference?

Naming is important. Events are facts that something happened. They should be named in the past tense which reflects what occurred. Examples are OrderPlaced, ShipmentReceived, InventoryAdjusted, and PaymentProcessed. These are the result of specific business concepts.

Full Cycle

So how do commands and events fit together? Since Commands are about invoking intent, and Events are about indicating that something occurred, you can see how the result of a command can be publishing an event.

First, we have a client/browser making a call to our HTTP API. Let’s say its to place an order.

In this specific case, we want to just accept the incoming HTTP request and capture the relevant data and send a PlaceOrder command to a queue on our message broker so we can process the message asynchronously. At which point we can then immediately return the client/browser that we accepted the request and are processing it.

Asynchronously the command handler can pull the message from the queue and execute whatever behavior is required to place the order.

The result of this is now we are going to publish an OrderPlaced event to a topic on the message broker.

We have 2 different consumers for the OrderPlaced event. One is to send an email to the customer saying thank you for your order. The other consumer might be to process their credit card and charge them for the order.

Commands & Events

To summarize commands and events we can compare and contrast their purpose, ownership, consumers, senders, and naming.

Commands & Events: What's the difference?

Join!

Developer-level members of my YouTube channel or Patreon get access to a private Discord server to chat with other developers about Software Architecture and Design as well as access to source code for any working demo application that I post on my blog or YouTube. Check out the YouTube Membership or Patreon for more info.

Follow @CodeOpinion on Twitter

Software Architecture & Design

Get all my latest YouTube Vidoes and Blog Posts on Software Architecture & Design

Asynchronous Request-Response Pattern for Non-Blocking Workflows

What’s the asynchronous request-response pattern for? We’re used to synchronous communication. You make a request to another service and get a response. When you move to asynchronous communication, you often think of messages as fire-and-forget. You send a command to a queue, and the consumer handles it asynchronously. Because of the temporal decoupling, you don’t know when the message was processed or what the result was. However, there is a solution! Let me explain how you can use the request-response pattern to reply sender once a message is processed.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

Blocking Synchronous

Most developers are familiar with blocking synchronous calls. If you make an HTTP call to a service, you’re making a blocking synchronous call.

When Service A makes a blocking synchronous call to Service B, it must wait to get the response (or acknowledgment) that the request is completed. There are many situations where this is entirely appropriate, such as in client or UI code. UI code reaching out to get data from a service is naturally blocking request-response.

However, service to service communication using blocking synchronous calls has complexity. As an example, if an order is placed within the Sales service, it makes a blocking synchronous call to the Billing service to charge the customer’s credit card or create an invoice.

Once that blocking call succeeds, then needs to make a blocking synchronous call to the warehouse service in order to allocate the product and create the shipping label.

This entire process is blocking and is temporally coupled. Both Billing and Warehouse services need to be available in order for the Sales service to place an order. Also since we lack a distributed transaction, we can be left with an inconsistent expected state if there is a failure. If the request to Billing was successful, but the request to the Warehouse failed, we now need to develop some resiliency to make another call back to the Billing service to refund the order. But what if that request fails? This isn’t resilient at all.

Asynchronous Request-Response

One solution to this problem is to remove the temporal coupling by using asynchronous request-response. This way each service can operate independently without requiring the other service to be available and able to process requests. To do this we can leverage asynchronous messaging and also apply the request-response pattern.

Here’s how asynchronous request-response works. First, the producer will send a message to a queue.

Asynchronous Request-Response Pattern for Non-Blocking Workflows

The consumer will process that message asynchronously.

Asynchronous Request-Response Pattern for Non-Blocking Workflows

Once the consumer has processed the message, it will create a reply message and send it to an entirely different queue.

Asynchronous Request-Response Pattern for Non-Blocking Workflows

The producer will then consume the reply message from the reply queue.

Asynchronous Request-Response Pattern for Non-Blocking Workflows

So now let’s jump back to the example of Sales, Billing, and Warehouse services. Using asynchronous messaging and the request-response pattern, we remove the temporal coupling and have each service work independently.

When an order is placed in the sales service, we’ll have an orchestrator that will send a Bill Order command to queue on our message broker.

Once Billing consumes that message, it will then send an Order Billed reply message that the Orchestrator will consume.

Once the Orchestrator consumes the Order Billed reply message, it will then create and send a Create Shipping Label command that the Warehouse service will consume.

Once the Warehouse has processed the message it will create a Shipping Label Created reply message that the Orchestrator will consume.

Once the Orchestrator has processed the reply, it changes the status of the order that was placed to Ready To Ship.

Here’s what our Orchestrator (NServiceBus Saga) looks like. It’s handling the appropriate reply messages and sending new commands (messages) to the broker as an asynchronous workflow.

Because all of this work is done using non-blocking asynchronous messaging, none of the services must available when an order is placed. They are all working independently processing messages in isolation.

The asynchronous request-response pattern allows you to tell a sender that the message has been processed and what the outcome or result was. You can leverage this to then build workflows to involve many different services all in a non-blocking way.

Join!

Developer-level members of my YouTube channel or Patreon get access to a private Discord server to chat with other developers about Software Architecture and Design. As well as access to source code for any working demo application that I post on my blog or YouTube. Check out the YouTube Membership or Patreon for more info.

Follow @CodeOpinion on Twitter

Software Architecture & Design

Get all my latest YouTube Vidoes and Blog Posts on Software Architecture & Design

Building a Webhooks System with Event Driven Architecture

Do you need to integrate with external systems or services? Leveraging an event driven architecture enables you to build a webhooks system that can be decoupled from your main application code. Enabling you to call external systems that have subscribed via webhooks in complete isolation from your application code.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.


In-Process

The simplest approach to building a webhooks system is to make calls in-process to the external HTTP APIs that want to be notified when we actually make some type of state change within our system.

For example, we have an e-commerce application where a user places an order. When this occurs, the application must persist the order data to our database.

Once the order is saved to our database, we then make an HTTP call to the 3rd part external HTTP API.

There are a few issues with this simplistic approach. The first is that because it’s in-process, the latency added to calling the external HTTP is added to the overall request the client made to place the order. Meaning this is blocking the client from getting their result of trying to place their order.

If the external HTTP API accepts our HTTP request but takes a long time to handle it, this could have a very negative impact on our own client. Do we have a timeout? What happens if the external HTTP API is unavailable and we can’t connect? Do we retry? All of this is adding latency to the overall call from our client.

Ideally, we separate placing an order with the integration (webhooks) to the external HTTP APIs.

Publish-Subscribe

We can leverage event driven architecture to decouple the concerns of saving the order and doing our webhooks integrations.

After the application (producer) has saved the order to the database, it then publishes an OrderPlaced event to a topic on our message broker. At this point, the Application can return back to the client.

Building a Webhooks System with Event Driven Architecture

Our webhook system can be a separate logical and/or physical component that is a consumer of that OrderPlaced Event by subscribing to the Topic on the message broker.

Building a Webhooks System with Event Driven Architecture

When it consumes the OrderPlaced event, it can then make the HTTP call to the external HTTP APIs.

Building a Webhooks System with Event Driven Architecture

Now if there is latency with one of the external HTTP APIs that doesn’t affect placing the order from our client. That’s already done and now completely separated since we’ve moved to asynchronous messaging.

Example

An example of this is done in the eShopOnContainers sample application. It does exactly have I have it outlined above.

It has a consumer that handles the OrderStatusChangedToPaidIntegrationEvent. When this event is consumed, it gets all the webhook subscriptions and then sends all the HTTP requests out.

Below is the implementation of the IWebhooksSender which makes the HTTP calls to the external HTTP APIs and sends them the webhook data.

More isolation

There’s one issue with the eShopOnContainers example above.

There likely would be multiple webhooks subscriptions that we would need to handle. The issue with this now is that if we do all HTTP requests in the same process, that means that each HTTP request will add latency to the overall processing of the event. What happens if one of the HTTP APIs fails to connect? What happens if one takes a really long time complete? We’re in a similar situation as before where we want to isolate work into a very specific task.

Building a Webhooks System with Event Driven Architecture

To accomplish this, when we receive the OrderPlaced event, we can look at all the webhook subscriptions we have, create a command, and send it to a queue on our message broker.

As an example, if there were three different webhook subscriptions, we would create three commands, SendOrderPlacedWebhookCommand.

Each command would then also be processed by our webhook system asynchronously where it would pull each message off the queue and then send the HTTP request to the appropriate external HTTP API.

After it finished processing the first command, it would then pick up the second command and perform the HTTP call.

What this now does is separate each individual webhook into its own unit of execution.

Now if one HTTP call fails or takes a long time, it is totally independent of any other.

Webhooks

Using an event driven architecture and messaging can facilitate building a webhooks system that can be very robust, fault-tolerant, resilient, and decoupled from your primary application code.

Follow @CodeOpinion on Twitter

Software Architecture & Design

Get all my latest YouTube Vidoes and Blog Posts on Software Architecture & Design