Extracting the Delivery Service - Step 3: define standalone Delivery Service

The previous post described the second step of the refactoring process, which consisted of splitting the ftgo database schema and defining an ftgo_delivery_service schema.

The third step of the refactoring process is to define a standalone Delivery Service and deploy it.

The following diagram shows the design:

The Delivery Service’s API consists of:

  • A REST API, which is implemented by the DeliveryController
  • A request/asynchronous response-style API, which is implemented by DeliveryServiceCommandHandlers, that will eventuallybe used by the FTGO monolith for scheduling and cancelling deliveries
  • An event publishing API, which is implemented byDeliveryEventPublisher, that publishes events when a courier’s schedule has been updated. It’s used instead of database triggers to replicate updates to courier’s schedules to the monolith. The FTGO monolith now contains a OrderServiceEventHandlers, which subscribes to the events published by Delivery Management and updates its local data.

Module structure

The following diagram shows the new module structure:

There are the following modules:

  • ftgo-delivery-backend* - previously these were the ftgo-delivery-service* modules
  • ftgo-delivery-service - a new module, which contains the Delivery Service’s main class and the DeliveryServiceCommandHandlers. It reuses the ftgo-delivery-backend module from the monolith rather than implementing the delivery management logic from scratch.

The event-based data integration glue is implemented by classes in the following modules:

  • ftgo-delivery-backend - contains the DeliveryEventPublisher class.
  • ftgo-order-service - contains the OrderServiceEventHandlers class.

Since these modules are part of the FTGO monolith, it uses the same event-based mechanism internally.

Why replace triggers with events?

One benefit of using triggers to synchronize two databases is that it doesn’t require any changes to the code. The synchronization is handled entirely by the database. A significant drawback, however, of using triggers is that it results in tight design-time and runtime coupling between the two databases. There is design-time coupling between the database, because a trigger has knowledge of both databases. There is also runtime coupling since both databases are updated within a single transaction.

Another drawback of using triggers is that the coupling makes it difficult to test the newly extracted service in isolation. Consider, for example, a test that verifies that the Delivery Service correctly processes a ScheduleDelivery command message. If a trigger replicates updates to a Courier’s schedule from ftgo_delivery_service database to the ftgo database then the test must correctly setup that database as well.

A much better approach is to use events to replicate changes. The Delivery Service can, for example, publish domain events when it updates a Courier’s schedule. The FTGO application subscribes to those events and updates its database.

An event-based replication mechanism has the following benefits:

  • Reduced design-time coupling - services communicate via APIs rather than access each other’s implementation details
  • Eliminates runtime coupling - there is no longer runtime coupling between the services
  • Improved testability - a test can easily verify that a service emits the expected events

It also has a couple of drawbacks. The first drawback of using events is that you need to change the application code to publish and consume events. In particular, modifying all of the places that publish events in a monolithic application might be prohibitively time consuming and error-prone.

The second drawback of using events to replicate changes is that it is eventually consistent. Unlike triggers, which execute within the ACID transaction that updates the source database, an event handler runs in a separate database transaction For example, the FTGO application executes the acceptOrder() command in a single transaction, which accepts the Order in the ftgo database, schedules the Delivery in the ftgo_delivery_service database, and replicates the changes (via a trigger) back to the ftgo database. In contrast, the event-based design uses two transactions. The first transaction accepts the Order in the ftgo database, and schedules the Delivery in the ftgo_delivery_service database. The second transaction replicates the changes back to the ftgo database. As a result, the acceptOrder() command no longer updates the Courier’s schedule.

In the future, the FTGO application might use events. But for now, we’ll just change Delivery Management to publish events it’s a relatively small change that makes it much easier to test the Delivery Service.

About DeliveryServiceComponentTest

Because the Delivery Service uses events rather than triggers to replicate changes to the FTGO application it’s straightforward to test the service in isolation. DeliveryServiceComponentTest implements a component test for the Delivery Service. The following diagram shows how this test works:

It sets up couriers and restaurants (normally replicated from the ftgo database via triggers) using JPA. DeliveryServiceComponentTest then sends a command message to the Delivery Service and asserts that it publishes the expected events.

Deploying the Delivery Service

Like the FTGO application, the Delivery Service is a Spring Boot application that is deployed a Docker container. The ftgo-delivery-service/Dockerfile file defines the container image. The docker-compose.yml file defines at ftgo-delivery-service container along with the infrastructure services needed for transactional messaging: Apache Zookeeper, Apache Kafka, and Eventuate Tram CDC.

Git commits

These changes are in the extract-delivery-service-03-define-service branch and consist of the following commits:

What’s next

About Microservices.io

Microservices.io is brought to you by Chris Richardson. Experienced software architect, author of POJOs in Action, the creator of the original CloudFoundry.com, and the author of Microservices patterns.

Chris helps clients around the world adopt the microservice architecture through consulting engagements, and training classes and workshops.

Learn how to create a service template and microservice chassis

Take a look at my Manning LiveProject that teaches you how to develop a service template and microservice chassis.

New virtual bootcamp: Distributed data patterns in a microservice architecture

My virtual bootcamp, distributed data patterns in a microservice architecture, is now open for enrollment!

It covers the key distributed data management patterns including Saga, API Composition, and CQRS.

It consists of video lectures, code labs, and a weekly ask-me-anything video conference repeated in multiple timezones.

The regular price is $395/person but use coupon WSSEULWL to sign up for $190 (valid until November 30th, 2022). There are deeper discounts for buying multiple seats.

Learn more

Signup for the newsletter


LEARN about microservices

Chris offers numerous resources for learning the microservice architecture.

Training classes

Chris teaches comprehensive workshops, training classes and bootcamps for executives, architects and developers to help your organization use microservices effectively.

Avoid the pitfalls of adopting microservices and learn essential topics, such as service decomposition and design and how to refactor a monolith to microservices.

Delivered in-person and remotely.


Get the book: Microservices Patterns

Read Chris Richardson's book:

Example microservices applications

Want to see an example? Check out Chris Richardson's example applications. See code

BUILD microservices

Ready to start using the microservice architecture?

Consulting services

Engage Chris to create a microservices adoption roadmap and help you define your microservice architecture,


The Eventuate platform

Use the Eventuate.io platform to tackle distributed data management challenges in your microservices architecture.

Eventuate is Chris's latest startup. It makes it easy to use the Saga pattern to manage transactions and the CQRS pattern to implement queries.

ASSESS your architecture

Assess your application's microservice architecture and identify what needs to be improved.

Consulting services

Engage Chris to conduct an architectural assessment.


Self assessment

Alternatively, conduct a self-assessment using the Microservices Assessment Platform.


Join the microservices google group

Posts

24 Jul 2017 » Revised data patterns

Copyright © 2021 Chris Richardson • All rights reserved • Supported by Kong.