MicroStream with Helidon MP

Helidon is a collection of Java libraries for writing microservices that run on a fast web core powered by Netty. The Helidon MP variant includes the MicroProfile specifications and programming against it feels familiar for enterprise java developers as all standard Jakarta EE APIs are available.
There exists also the Helidon SE variant which is a group of reactive, non-blocking microframeworks.

MicroStream is integrated with Helidon, which means that you can add MicroStream and the integration code by adding some Helidon-provided dependencies. It is integrated within the Helidon SE variant but some operations within MicroStream are blocking. So it might not be the best combination since we need to protect a single resource, your database, that is accessed by multiple threads concurrently.

This blog describes how you can make use of the integration with Helidon MP.

Create project

Creating a Helidon MP project can be done in two ways. You can either use the Helidon Starter webpage or from the Helidon CLI with helidon init command to create a basic project structure using Helidon MP.

Once you have the project, you can add the MicroStream integration code by adding the following dependency.

        <dependency>
            <groupId>io.helidon.integrations.microstream</groupId>
            <artifactId>helidon-integrations-microstream-cdi</artifactId>
        </dependency>

Configuration

As a minimum, you need to define the directory where the MicroStream serialisation process writes the binary data. This is done by defining the configuration values using the MicroProfile Config support. This means it can be done by adding the values in the META-INF/microprofile-config.properties file, or any other source supported by MicroProfile Config.

The key values are described on the MicroStream documentation page. And these keys should be prefixed to indicate a certain StorageManager. Since you can define and use multiple StorageManagers for your application, the groups and discriminate the configuration values for each StorageManager.

[dt_code]one.microstream.bookstore.storage-directory=microstream-data[/dt_code]

When defining the above value, you set the storage directory configuration value of the StorageManager that you identify with one.microstream.bookstore.

Define Root

Besides the configuration values for the StorageManager, defining the root object of your Object graph is another important requirement for your application.

You can define this easily using a CDI producer that you define within your code. At this central location, you can get hold of the defined StorageManager by the integration code, and define a Root object. And in the same time expose this as a CDI bean so that you can inject it into any other CDI bean within your application, just as you can use the StorageManager.

@ApplicationScoped
public class RootProducer {

    @Inject
    @MicrostreamStorage(configNode = "one.microstream.bookstore")
    private EmbeddedStorageManager storageManager;

    @Produces
    public Root produceInitializedRoot() {
        Root root = (Root) storageManager.root();
        if (root == null) {
           // Define and initialise root with StorageManager.
        } else {
            root.setStorageManager(storageManager);
        }
        return root;
    }
}

 

Health and Metrics

The MicroProfile Health and Metrics specifications are two important aspects that help to increase the observability of your application. The MicroStream integration within Helidon comes with artefacts that provide some specific functionality for MicroStream.

First, you need to add some dependencies to your project.

    <dependency>
        <groupId>io.helidon.integrations.microstream</groupId>
        <artifactId>helidon-integrations-microstream-health</artifactId>
    </dependency>

    <dependency>
        <groupId>io.helidon.integrations.microstream</groupId>
        <artifactId>helidon-integrations-microstream-metrics</artifactId>
    </dependency>

These dependencies contain the basic functionality related to Heath and Metrics that are also useable with Helidon SE. So we need to define the ‘glue’ code that makes the Health Checks and Metrics available through the MicroProfile Specifications.

For the Health checks, we can define the CDI bean implementing the HealthCheck interface and forward the implementation to the MicrostreamHealthCheck code.

@ApplicationScoped
@Liveness
public class MicroStreamHealth implements HealthCheck {

    @Inject
    @MicrostreamStorage(configNode = "one.microstream.storage.bookstore")
    private EmbeddedStorageManager storageManager;

    @Override
    public HealthCheckResponse call() {
        return MicrostreamHealthCheck.create(storageManager)
                .call();
    }
}

 

The check is UP when the StorageManager is running.

For the Metrics support, we can register the MicroStream metrics, like the size of the binary data that is stored, when the application starts up. When the metrics are registered, they are called whenever a metrics request is made.

@ApplicationScoped
public class MicroStreamMetrics {

    @Inject
    @MicrostreamStorage(configNode = "one.microstream.storage.bookstore")
    private EmbeddedStorageManager storageManager;

    public void onStart(@Observes @Initialized(ApplicationScoped.class) Object pointless) {
        RegistryFactory metricsRegistry = RegistryFactory.getInstance();

        MicrostreamMetricsSupport microstreamMetrics = MicrostreamMetricsSupport
                .builder(storageManager)
                .registryFactory(metricsRegistry)
                .build();

        microstreamMetrics.registerMetrics();
    }
}

Example

For a demo application, have a look at the repository on GitHub. It has a folder called integrated that contains a demo application using Helidon MP and the integrated MicroStream code.

It demonstrates the configuration as discussed in this text and provides a few endpoints to query, update and insert some data.

Conclusion

With the integration into Helidon MP, it becomes easy to define and configure the StorageManager and the Root object in a central location. From that point onward, they are available as CDI beans and can be used throughout the application to read and store the data from your Object Graph.

 

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

Store State of a Background process with MicroStream

Next Post

Some Data Model considerations for searching and indexing with MicroStream

Related Posts
Secured By miniOrange