Implementing The Outbox-Pattern With Kafka – Part 1: Writing In The Outbox-Table

This article is part of a Blog-Series

Based on a very simple example-project
we will implemnt the Outbox-Pattern with Kafka.

TL;DR

In this part, we will implement the outbox (aka: the queueing of the messages in a database-table).

The Outbox Table

The outbox is represented by an additionall table in the database.
This table acts as a queue for messages, that should be send as part of the transaction.
Instead of sending the messages, the application stores them in the outbox-table.
The actual sending of the messages occures outside of the transaction.

Because the messages are read from the table outside of the transaction context, only entries related to sucessfully commited transactions are visible.
Hence, the sending of the message effectively becomes a part of the transaction.
It happens only, if the transaction was successfully completed.
Messages associated to an aborted transaction will not be send.

The Implementation

No special measures need to be taken when writing the messages to the table.
The only thing to be sure of is that the writing takes part in the transaction.

In our implementation, we simply store the serialized message, together with a key, that is needed for the partitioning of your data in Kafka, in case the order of the messages is important.
We also store a timestamp, that we plan to record as Event Time later.

One more thing that is worth noting is that we utilize the database to create an unique record-ID.
The generated unique and monotonically increasing id is required later, for the implementation of Exactly-Once semantics.

The SQL for the table looks like this:

CREATE TABLE outbox (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  key VARCHAR(127),
  value varchar(1023),
  issued timestamp
);

Decoupling The Business Logic

In order to decouple the business logic from the implementation of the messaging mechanism, I have implemented a thin layer, that uses Spring Application Events to publish the messages.

Messages are send as a subclass of ApplicationEvent:

publisher.publishEvent(
  new UserEvent(
    this,
    username,
    CREATED,
    ZonedDateTime.now(clock)));

The event takes a key (username) and an object as value (an instance of an enum in our case).
An EventListener receives the events and writes them in the outbox table:

@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void onUserEvent(OutboxEvent event)
{
  try
  {
    repository.save(
        event.getKey(),
        mapper.writeValueAsString(event.getValue()),
        event.getTime());
  }
  catch (JsonProcessingException e)
  {
    throw new RuntimeException(e);
  }
}

The @TransactionalEventListener is not really needed here.
A normal EventListener would also suffice, because spring immediately executes all registered normal event listeners.
Therefore, the registered listeners would run in the same thread, that published the event, and participate in the existing transaction.

But if a @TransactionalEventListener is used, like in our example project, it is crucial, that the phase is switched to BEFORE_COMMIT when the Outbox Pattern is introduced.
This is, because the listener has to be executed in the same transaction context in which the event was published.
Otherwise, the writing of the messages would not be coupled to the success or abortion of the transaction, thus violating the idea of the pattern.

May The Source Be With You!

Since this part of the implementation only stores the messages in a normal database, it can be published as an independent component that does not require any dependencies on Kafka.
To highlight this, the implementation of this step does not use Kafka at all.
In a later step, we will separate the layer, that decouples the business code from our messaging logic in a separate package.

The complete source code of the example-project can be cloned here:

This version only includes the logic, that is needed to fill the outbox-tabel.
Reading the messages from this table and sending them through Kafka will be the topic of the next part of this blog-series.

The sources include a Setup for Docker Compose, that can be run without compiling
the project. And a runnable README.sh, that compiles and run the application and illustrates the example.

Implementing The Outbox-Pattern With Kafka – Part 0: The example

This article is part of a Blog-Series

Based on a very simple example-project
we will implemnt the Outbox-Pattern with Kafka.

TL;DR

In this part, a small example-project is introduced, that features a component, which has to inform another component upon every succsessfully completed operation.

The Plan

In this mini-series I will implement the Outbox-Pattern
as described on Chris Richardson’s fabolous website microservices.io.

The pattern enables you, to send a message as part of a database transaction in a reliable way, effectively turining the writing of the data
to the database and the sending of the message into an atomic operation:
either both operations are successful or neither.

The pattern is well known and implementing it with Kafka looks like an easy straight forward job at first glance.
However, there are many obstacles that easily lead to an incomplete or incorrect implementation.
In this blog-series, we will circumnavigate these obstacles together step by step.

The Example Project

To illustrate our implementation, we will use a simple example-project.
It mimics a part of the registration process for an web application:
a (very!) simplistic service takes registration orders for new users.

  • Successfull registration requests will return a 201 (Created), that carries the URI, under which the data of the newly registered user can be accessed in the Location-header:


    echo peter | http :8080/users
    
    HTTP/1.1 201 
    Content-Length: 0
    Date: Fri, 05 Feb 2021 14:44:51 GMT
    Location: http://localhost:8080/users/peter
    

  • Requests to registrate an already existing user will result in a 400 (Bad Request):

    echo peter | http :8080/users
    
    HTTP/1.1 400 
    Connection: close
    Content-Length: 0
    Date: Fri, 05 Feb 2021 14:44:53 GMT
    

  • Successfully registrated users can be listed:

    http :8080/users
    
    HTTP/1.1 200 
    Content-Type: application/json;charset=UTF-8
    Date: Fri, 05 Feb 2021 14:53:59 GMT
    Transfer-Encoding: chunked
    
    [
        {
            "created": "2021-02-05T10:38:32.301",
            "loggedIn": false,
            "username": "peter"
        },
        ...
    ]
    

The Messaging Use-Case

As our messaging use-case imagine, that there has to happen several processes after a successful registration of a new user.
This may be the generation of an invoice, some business analytics or any other lengthy process that is best carried out asynchronously.
Hence, we have to generate an event, that informs the responsible services about new registrations.

Obviously, these events should only be generated, if the registration is completed successfully.
The event must not be fired, if the registration is rejected, because a duplicate username.

On the other hand, the publication of the event must happen reliably, because otherwise, the new might not be charged for the services, we offer…

The Transaction

The users are stored in a database and the creation of a new user happens in a transaction.
A “brilliant” colleague came up with the idea, to trigger an IncorrectResultSizeDataAccessException to detect duplicate usernames:

User user = new User(username);
repository.save(user);
// Triggers an Exception, if more than one entry is found
repository.findByUsername(username);

The query for the user by its names triggers an IncorrectResultSizeDataAccessException, if more than one entry is found.
The uncaught exception will mark the transaction for rollback, hence, canceling the requested registration.
The 400-response is then generated by a corresponding ExceptionHandler:

@ExceptionHandler
public ResponseEntity incorrectResultSizeDataAccessException(
    IncorrectResultSizeDataAccessException e)
{
  LOG.info("User already exists!");
  return ResponseEntity.badRequest().build();
}

Please do not code this at home…

But his weired implementation perfectly illustrates the requirements for our messaging use-case:
The user is written into the database.
But the registration is not successfully completed until the transaction is commited.
If the transaction is rolled back, no message must be send, because no new user was registered.

Decoupling with Springs EventPublisher

In the example implementation I am using an EventPublisher to decouple the business logic from the implementation of the messaging.
The controller publishes an event, when a new user is registered:

publisher.publishEvent(new UserEvent(this, usernam));

A listener annotated with @TransactionalEventListener receives the events and handles the messaging:

@TransactionalEventListener
public void onUserEvent(UserEvent event)
{
    // Sending the message happens here...
}

In non-critical use-cases, it might be sufficient to actually send the message to Kafka right here.
Spring ensures, that the message of the listener is only called, if the transaction completes successfully.
But in the case of a failure this naive implementation can loose messages.
If the application crashes, after the transaction has completed, but before the message could be send, the event would be lost.

In the following blog posts, we will step by step implement a solution based on the Outbox-Pattern, that can guarantee Exactly-Once semantics for the send messages.

May The Source Be With You!

The complete source code of the example-project can be cloned here:

It includes a Setup for Docker Compose, that can be run without compiling
the project. And a runnable README.sh, that compiles and run the application and illustrates the example.

How To Instantiatiate Multiple Beans Dinamically in Spring-Boot Depending on Configuration-Properties

TL;DR

In this mini-HowTo I will show a way, how to instantiate multiple beans dinamically in Spring-Boot, depending on configuration-properties.
We will:

  • write a ApplicationContextInitializer to add the beans to the context, before it is refreshed
  • write a EnvironmentPostProcessor to access the configured configuration sources
  • register the EnvironmentPostProcessor with Spring-Boot

Write an ApplicationContextInitializer

Additionally Beans can be added programatically very easy with the help of an ApplicationContextInitializer:

@AllArgsConstructor
public class MultipleBeansApplicationContextInitializer
    implements
      ApplicationContextInitializer
{
  private final String[] sites;

  @Override
  public void initialize(ConfigurableApplicationContext context)
  {
    ConfigurableListableBeanFactory factory =
        context.getBeanFactory();
    for (String site : sites)
    {
      SiteController controller =
          new SiteController(site, "Descrition of site " + site);
      factory.registerSingleton("/" + site, controller);
    }
  }
}

This simplified example is configured with a list of strings that should be registered as controllers with the DispatcherServlet.
All “sites” are insances of the same controller SiteController, which are instanciated and registered dynamically.

The instances are registered as beans with the method registerSingleton(String name, Object bean)
of a ConfigurableListableBeanFactory that can be accessed through the provided ConfigurableApplicationContext

The array of strings represents the accessed configuration properties in the simplified example.
The array will most probably hold more complex data-structures in a real-world application.

But how do we get access to the configuration-parameters, that are injected in this array here…?

Accessing the Configured Property-Sources

Instantiating and registering the additionally beans is easy.
The real problem is to access the configuration properties in the early plumbing-stage of the application-context, in that our ApplicationContextInitializer runs in:

The initializer cannot be instantiated and autowired by Spring!

The Bad News: In the early stage we are running in, we cannot use autowiring or access any of the other beans that will be instantiated by spring – especially not any of the beans, that are instantiated via @ConfigurationProperties, we are intrested in.

The Good News: We will present a way, how to access initialized instances of all property sources, that will be presented to your app

Write an EnvironmentPostProcessor

If you write an EnvironmentPostProcessor, you will get access to an instance of ConfigurableEnvironment, that contains a complete list of all PropertySource‘s, that are configured for your Spring-Boot-App.

public class MultipleBeansEnvironmentPostProcessor
    implements
      EnvironmentPostProcessor
{
  @Override
  public void postProcessEnvironment(
      ConfigurableEnvironment environment,
      SpringApplication application)
  {
    String sites =
        environment.getRequiredProperty("juplo.sites", String.class);

    application.addInitializers(
        new MultipleBeansApplicationContextInitializer(
            Arrays
                .stream(sites.split(","))
                .map(site -> site.trim())
                .toArray(size -> new String[size])));
  }
}

The Bad News:
Unfortunately, you have to scan all property-sources for the parameters, that you are interested in.
Also, all values are represented as stings in this early startup-phase of the application-context, because Spring’s convenient conversion mechanisms are not available yet.
So, you have to convert any values by yourself and stuff them in more complex data-structures as needed.

The Good News:
The property names are consistently represented in standard Java-Properties-Notation, regardless of the actual type (.properties / .yml) of the property source.

Register the EnvironmentPostProcessor

Finally, you have to register the EnvironmentPostProcessor with your Spring-Boot-App.
This is done in the META-INF/spring.factories:

org.springframework.boot.env.EnvironmentPostProcessor=\
  de.juplo.demos.multiplebeans.MultipleBeansEnvironmentPostProcessor

That’s it, your done!

Source Code

You can find the whole source code in a working mini-application on juplo.de and GitHub:

Other Blog-Posts On The Topic

  • The blog-post Dynamic Beans in Spring shows a way to register beans dynamically, but does not show how to access the configuration. Also, meanwhile another interface was added to spring, that facilitates this approach: BeanDefinitionRegistryPostProcessor
  • Benjamin shows in How To Create Your Own Dynamic Bean Definitions In Spring, how this interface can be applied and how one can access the configuration. But his example only works with plain Spring in a Servlet Container

Actuator HTTP Trace Does Not Work With Spring Boot 2.2.x

TL;DR

In Spring Boot 2.2.x, you have to instanciate a @Bean of type InMemoryHttpTraceRepository to enable the HTTP Trace Actuator.

Jump to the explanation of and example code for the fix

Enabling HTTP Trace — Before 2.2.x...

Spring Boot comes with a very handy feature called Actuator.
Actuator provides a build-in production-ready REST-API, that can be used to monitor / menage / debug your bootified App.
To enable it — prior to 2.2.x —, one only had to:

  1. Specifiy the dependency for Spring Boot Actuator:

    <dependency>
      <groupId>org.springframework.boot
      <artifactId>spring-boot-starter-actuator
    </dependency>
    
    
  2. Expose the needed endpoints via HTTP:

    management.endpoints.web.exposure.include=*
    
    • This exposes all available endpoints via HTTP.
    • Advise: Do not copy this into a production config
      (Without thinking about it twice and — at least — enable some security measures to protect the exposed endpoints!)

The problem: It simply does not work any more in 2.2 :(

But…

  • If you upgrade your existing app with a working httptrace-actuator to Spring Boot 2.2.x, or
  • If you start with a fresh app in Spring Boot 2.2.x and try to enable the httptrace-actuator as described in the documentation

…it simply does not work at all!

The Fix

The simple fix for this problem is, to add a @Bean of type InMemoryHttpTraceRepository to your @Configuration-class:

@Bean
public HttpTraceRepository htttpTraceRepository()
{
  return new InMemoryHttpTraceRepository();
}

The Explanation

The cause of this problem is not a bug, but a legitimate change in the default configuration.
Unfortunately, this change is not noted in the according section of the documentation.
Instead it is burried in the Upgrade Notes for Spring Boot 2.2

The default-implementation stores the captured data in memory.
Hence, it consumes much memory, without the user knowing, or even worse: needing it.
This is especially undesirable in cluster environments, where memory is a precious good.
And remember: Spring Boot was invented to simplify cluster deployments!

That is, why this feature is now turned of by default and has to be turned on by the user explicitly, if needed.

XPath 2.0 deep-equal Does Not Match Like Expected – The Problem With Whitespace

I just stumbled accros a problem with the deep-equal()-method introduced by XPath 2.0.
It costs me two hours at minimum to find out, what was going on.
So I want to share this with you, in case your are wasting time on the same problem and try to find a solution via google ;)

If you never heard of deep-equal() and just wonder how to compare XML-nodes in the right way, you should probably read this exelent article about equality in XSLT as a starter.

My Problem

My problem was, that I wanted to parse/output a node only, if there exists no node on the ancestor-axis, that has a exact duplicate of that node as a direct child.

The Difference Between A Comparison With = And With deep-equal()

If you just use simple equality (with = or eq), the two compared nodes are converted into strings implicitly.
That is no problem, if you are comparing attributes, or nodes, that only contain text.
But in all other cases, you will only compare the text-contents of the two nodes and their children.
Hence, if they differ only in an attribute, your test will report that they are equal, which might not be what you are expecting.

For example, the XPath-expression

//child/ref[ancestor::parent/ref=.]

will match the <ref>-node with @id='bar', that is nested insiede the <child>-node in this example-XML, what I was not expecting:

<root>
  <parent>
    <ref id="foo"><content>Same Text-Content</content></ref>
    <child>
      <ref id="bar"><content>Same Text-Content</content></ref>
    </child>
  <parent>
<list>

So, what I tried, after I found out about deep-equal() was the following Xpath-expression, which solves the problem in the above example:

//child/ref[deep-equal(ancestor::parent/ref,.)]

The Unexpected Behaviour Of deep-equal()

But, moving on I stumbled accross cases, where I was expecting a match, but deep-equal() does not match the nodes.
For example:

<root>
  <parent>
    <ref id="same">
      <content>Same Text-Content</content>
    </ref>
    <child>
      <ref id="same">
        <content>Same Text-Content</content>
      </ref>
    </child>
  <parent>
<list>

You probably catch the diffrenece at first glance, since I laid out the examples accordingly and gave you a hint in the heading of this post – but it really took me a long time to get that:

It is all about whitespace!

deep-equal() compares all child-nodes and only yields a match, if the compared nodes have exactly the same child-nodes.
But in the second example, the compared <ref>-nodes contain whitespace befor and after their child-node <content>.
And these whitespace are in fact implicite child-nodes of type text.
Hence, the two nodes in the second example differe, because the indentation on the second one has two more spaces.

The solution…?

Unfortunatly, I do not really know a good solution.
(If you come up with one, feel free to note or link it in the comments!)

The best solution would be an option additional argument for deep-equal(), that can be selected to tell the function to ignore such whitespace.
In fact, some XSLT-parsers do provide such an argument.

The only other solution, I can think of, is, to write another XSLT-script to remove all the whitespaces between tags to circumvent this at the first glance unexpected behaviour of deep-equal()

Funded by the Europian Union

This article was published in the course of a
resarch-project,
that is funded by the European Union and the federal state Northrhine-Wetphalia.


Europäische Union: Investitionen in unsere Zukunft - Europäischer Fonds für regionale Entwicklung
EFRE.NRW 2014-2020: Invesitionen in Wachstum und Beschäftigung

Problems Deploying A Spring-Boot-App As WAR

Spring-Boot-App Is Not Started, When Deployed As WAR

Recently, I had a lot of trouble, deploying my spring-boot-app as war under Tomcat 8 on Debian Jessie.
The WAR was found and deployed by tomcat, but it was never started.
Browsing the URL of the app resulted in a 404.
And instead of the fancy Spring-Boot ASCII-art banner, the only matching entry that showed up in my log-file was:

INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log Spring WebApplicationInitializers detected on classpath: [org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration$JerseyWebApplicationInitializer@1fe086c]

A blog-post from Stefan Isle lead me to the solution, what was going wrong.
In my case, there was no wrong version of Spring on the classpath.
But my WebApplicationInitializer was not found, because I had it compiled with a version of Java, that was not available on my production system.

WebApplicationInitializer Not Found Because Of Wrong Java Version

On my development box, I had compiled and tested the WAR with Java 8.
But on my production system, running Debian 8 (Jessie), only Java 7 was available.
And because of that, my WebApplicationInitializer

After installing Java 8 from debian-backports on my production system, like described in this nice debian-upgrade note, the WebApplicationInitializer of my App was found and everything worked like a charme, again.

Funded by the Europian Union

This article was published in the course of a
resarch-project,
that is funded by the European Union and the federal state Northrhine-Wetphalia.


Europäische Union: Investitionen in unsere Zukunft - Europäischer Fonds für regionale Entwicklung
EFRE.NRW 2014-2020: Invesitionen in Wachstum und Beschäftigung

Release Of A Maven-Plugin to Maven Central Fails With “error: unknown tag: goal”

error: unknown tag: goal

Releasing a maven-plugin via Maven Central does not work, if you have switched to Java 8.
This happens, because hidden in the oss-parent, that you have to configure as parent of your project to be able to release it via Sonatype, the maven-javadoc-plugin is configured for you.
And the version of javadoc, that is shipped with Java 8, by default checks the syntax of the comments and fails, if anything unexpected is seen.


Unfortunatly, the special javadoc-tag’s, like @goal or @phase, that are needed to configure the maven-plugin, are unexpected for javadoc.

Solution 1: Turn Of The Linting Again

As described elswehere, you can easily turn of the linting in the plugins-section of your pom.xml:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-javadoc-plugin</artifactId>
  <version>2.7</version>
  <configuration>
    <additionalparam>-Xdoclint:none</additionalparam>
  </configuration>
</plugin>

Solution 2: Tell javadoc About The Unknown Tags

Another not so well known approach, that I found in a fix for an issue of some project, is, to add the unknown tag’s in the configuration of the maven-javadoc-plugin:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-javadoc-plugin</artifactId>
  <version>2.7</version>
  <configuration>
    <tags>
      <tag>
        <name>goal</name>
        <placement>a</placement>
        <head>Goal:</head>
      </tag>
      <tag>
        <name>phase</name>
        <placement>a</placement>
        <head>Phase:</head>
      </tag>
      <tag>
        <name>threadSafe</name>
        <placement>a</placement>
        <head>Thread Safe:</head>
      </tag>
      <tag>
        <name>requiresDependencyResolution</name>
        <placement>a</placement>
        <head>Requires Dependency Resolution:</head>
      </tag>
      <tag>
        <name>requiresProject</name>
        <placement>a</placement>
        <head>Requires Project:</head>
      </tag>
    </tags>
  </configuration>
</plugin>

Funded by the Europian Union

This article was published in the course of a
resarch-project,
that is funded by the European Union and the federal state Northrhine-Wetphalia.


Europäische Union: Investitionen in unsere Zukunft - Europäischer Fonds für regionale Entwicklung
EFRE.NRW 2014-2020: Invesitionen in Wachstum und Beschäftigung