Chapter 0. Launching an energy-saving rocket to the stars

Welcome to the first chapter of a series of articles describing the decisions and challenges we faced (suffered and enjoyed) during our path towards the delivery of a brand-new service.

In this new challenge, we explored modern and mature technologies in the market to serve as productive examples which would allow us to define our standards for future services. To be the seed for our service development template.

The main goal is to end up with a service made by the best of the best in every aspect. Notice there is clearly a subjective approach to this. What is the…


Chapter N. Time to enjoy the dessert

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

You reached the release phase, we hope it took less than what it took to us. Once completed all the described steps, we got in our repository a robust, fault tolerant and fully documented and testable service that satisfies all the goals we decided.

Let’s recap the challenges we went through:

  1. Asynchronous: Avoid blocking the consumer while the request is being processed.
  2. Outbound pressure control: Protect the consumed services based on their SLA to avoid overflowing them
  3. Retry mechanism: Properly react when the consumed services are unavailable…

Chapter 8. Discoverable/Testable

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

In this chapter we are describing two key aspects of our service:

  • Discoverable: How we help consumers use it
  • Testable: How we help consumers and other DEXMA developers work with it

1. Discoverable: API Documentation

Regarding the first goal, we want to provide a complete, concise and always-up-to-date API documentation.

We chose Swagger to automatically provide a bottom-up approach for generating service’s documentation. This approach ensures that documentation is always aligned with code since it is a mirror of the code, actually, it is generated from the code.

This is how…


Chapter 7. Human-friendly software lifecycle

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

Our goal is to apply the demonstrated benefits of Behaviour Driven Development (BDD) to the selected technical stack of this component.

Our user story, besides the context and feature description, contains the Acceptance Criteria. Let’s focus on this, as it will be used during most part of the feature lifecycle: from the user story definition until the feature’s quality assurance.

Given a user story which Acceptance Criterion is written in human language, like this example:

A Cucumber test is directly created from the user story’s acceptance criteria…


Chapter 6. Caching

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

Our service receives IoT trends that come every hour from a large number of hardware devices, which do not change very often. One of the steps in our service logic consists of retrieving the datasource assigned to the IoT device. Since it would result in a call to our API for each device and hour, based on the initial assumption, we decided to add a client-side cache to keep this configuration and therefore avoid calling our API unnecessarily.

We are using Caffeine, a client-side cache, configured as…


Chapter 5. Profiling

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

Before releasing the service, we want to analyse the behaviour of the JVM with all these new technologies and ensure that the component will behave as expected on a high load scenario. From local machine we can easily profile the JVM with JConsole, jvisualvm, Java Mission Control, etc

But we want to go further, providing these profiling tools for the service when running on Kubernetes, and also offering metrics for Webflux reactor components.

In this stage we got the valuable assistance of our DevOps team mates. Most…


Chapter 4. Health check

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

As for any delivered service, we want to provide a simple but complete health check endpoint which will give us a summary of the status of the service itself and its collaborators (downstream services consumed).

To ensure that health check always responds immediately and it’s not impacted by the maximum connection limit defined for the consumed services (see previous Outbound pressure control chapter), we create a separate and independent web client for health check purposes. …


Chapter 3. Retry Policy

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

At this point, we need to define the retry policy to safely react when consumed services produce any error. We take advantage of retry policy also for delaying the request when the maximum number of connections is reached, as defined in previous chapter for configuring Outbound pressure control

In this case, to protect the consumed service, the request is delayed based on an exponential backoff retry policy, which ensures a later execution but prevents that the retry policy itself overloads the external service even more.

Retry policy…


Chapter 2: Outbound pressure control

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

In this chapter, we are describing our steps to protect the consumed services based on their SLA, limiting the maximum number of requests sent in parallel.

The chosen mechanism to avoid overflowing the consumed service is to define the maximum connections to keep open for each client. This is achieved by using the reactor HttpClient with a fixed connection provider (instead of the default elastic provider):

HttpClient
.create(ConnectionProvider.fixed(“ConsumedService”, maxConnections, acquireTimeout, maxIdleTime, maxLifeTime))

The maxConnections is defined as the max requests in parallel provided by the consumed service…


Chapter 1: Asynchronous

(This story begins in Chapter 0. Launching an energy-saving rocket to the stars)

Asynchronous is a broad term and may lead to misunderstanding. In our context, we need to receive the request, validate that it is correct, tell the client that we have properly received it and then process it in the background, decoupling this (maybe long) process from the caller. In other words, the connection is closed as soon as possible and the consumer just receives an acknowledgement.

Here came our first technological analysis and design decision. We needed to provide asynchronicity at server (Fire & Forget) and client…

Pau García

Software Engineer who loves to find the simplest and most robust solution for each use case by applying architectural, design and clean-code principles

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store