Quarkus - Unleash

Unleash is a feature toggle system, that gives you a great overview of all feature toggles across all your applications and services. Quarkus Unleash extension is client for Unleash.

Installation

If you want to use this extension, you need to add the quarkiverse-unleash extension first. In your pom.xml file, add:

<dependency>
    <groupId>io.quarkiverse.unleash</groupId>
    <artifactId>quarkus-unleash</artifactId>
    <version>1.8.0</version>
</dependency>

Usage

Unleash client

Assuming you have Unleash running on localhost:4242 you should add the following properties to your application.properties and fill in the values for url.

quarkus.unleash.url=http://localhost:4242/api

Once you have configured the properties, you can start using an Unleash-client.

@ApplicationScoped
public class TestService {

    @Inject
    Unleash unleash;

    public boolean isTest() {
        return unleash.isEnabled("quarkus.unleash.test");
    }
}

@FeatureToggle

By using the @FeatureToggle annotation there is a shortcut to inject feature toggle.

@ApplicationScoped
public class TestService {

    @FeatureToggle(name = "my-toggle")
    Instance<Boolean> myToggle;

    @FeatureToggle(name = "my-toggle", defaultValue = true)
    Instance<Boolean> myToggleDefault;

}

If the @FeatureToggle annotation is placed on a boolean field or method argument, an exception will be thrown at build time. @FeatureToggle should only be used with the Instance<Boolean> type.

@FeatureVariant

By using the @FeatureVariant annotation there is a shortcut to inject feature toggle variant or the payload of the variant.

@ApplicationScoped
public class TestService {

    @FeatureVariant(name = "toggle-variant")
    Instance<Variant> variant;

    @FeatureVariant(name = "toggle-payload")
    Instance<String> variant;

    @FeatureVariant(name = "toggle-variant-json")
    Instance<MyCustomJsonModel> variant;

}

Subscriber API

This extension supports the Subscriber API from the Unleash Client SDK for Java. It can be used by implementing the UnleashSubscriber interface as shown below.

import static io.getunleash.repository.FeatureToggleResponse.Status.CHANGED;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import jakarta.enterprise.context.ApplicationScoped;

import io.getunleash.FeatureToggle;
import io.getunleash.event.UnleashSubscriber;
import io.getunleash.repository.FeatureToggleResponse;
import io.quarkus.arc.Unremovable;
import io.quarkus.logging.Log;

@ApplicationScoped (1)
public class ToggleChangedLogger implements UnleashSubscriber {

    private static final Set<String> TOGGLE_NAMES = Set.of("my-toggle-1", "my-toggle-2");

    private final Map<String, Boolean> toggleValues = new HashMap<>();

    @Override
    public void togglesFetched(FeatureToggleResponse toggleResponse) {
        if (toggleResponse.getStatus() == CHANGED) {
            for (String toggleName : TOGGLE_NAMES) {
                FeatureToggle toggle = toggleResponse.getToggleCollection().getToggle(toggleName);
                if (toggle != null) {
                    Boolean previousValue = toggleValues.put(toggleName, toggle.isEnabled());
                    if (previousValue == null || previousValue != toggle.isEnabled()) {
                        String value = toggle.isEnabled() ? "enabled" : "disabled";
                        Log.infof("Feature toggle %s was just %s", toggleName, value);
                    }
                } else {
                    toggleValues.remove(toggleName);
                }
            }
        }
    }
}
1 The UnleashSubscriber implementation has to be a CDI bean.

Bootstrapping toggles from a JSON string

This extension supports bootstrapping the Unleash feature toggles from a JSON string. This can be especially useful for applications deployed in ephemeral containers where the access to the file system is sometimes restricted. See the Unleash documentation for more details about bootstrapping.

import jakarta.enterprise.context.ApplicationScoped;

import io.getunleash.repository.ToggleBootstrapProvider;
import io.quarkus.arc.Unremovable;

@ApplicationScoped (1)
@Unremovable (2)
public class TogglesBootstrapper implements ToggleBootstrapProvider {

    @Override
    public String read() {
        // Return a JSON string in the same format returned from /api/client/features (3)
    }
}
1 The ToggleBootstrapProvider implementation has to be a CDI bean.
2 The bean will be considered unused and will be automatically removed if it is not annotated with @Unremovable.
3 Examples can be found in the Unleash Client SDK for Java repository

Testing

To use the test extension, add this dependency to the project:

<dependency>
    <groupId>io.quarkiverse.unleash</groupId>
    <artifactId>quarkus-unleash-test</artifactId>
    <version>1.8.0</version>
    <scope>test</scope>
</dependency>

UnleashTestResource creates an instance of admin and standard Unleash clients just for testing. These instances are separate from the application instances.

@QuarkusTest
@QuarkusTestResource(UnleashTestResource.class)
public class BaseTest {

    @InjectUnleashAdmin
    UnleashAdmin admin;

    @InjectUnleash
    Unleash client;

    @Test
    public void test() {

        admin.toggleOff("toggle-1");
        admin.toggleOn("toggle-2");

        // wait for client change
        await().atLeast(12, SECONDS)
                .pollInterval(4, SECONDS)
                .until(() -> client.isEnabled("toggle-2"));

        boolean toggleOn = client.isEnabled("toggle-2");

        // ... test my application

    }
}

Dev-Services

Dev Services for Unleash is automatically enabled unless:

  • quarkus.unleash.devservices.enabled is set to false

  • quarkus.unleash.url is configured

Dev Service for Unleash relies on Docker to start the broker. If your environment does not support Docker, you will need to start the broker manually, or connect to an already running broker. You can configure the broker address using quarkus.unleash.url.

Extension Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

If DevServices has been explicitly enabled or disabled. DevServices is generally enabled by default, unless there is an existing configuration present.

When DevServices is enabled Quarkus will attempt to automatically configure and start a database when running in Dev or Test mode and when Docker is running.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_ENABLED

boolean

true

Optional fixed port the dev service will listen to.

If not defined, the port will be chosen randomly.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_PORT

int

Indicates if the Unleash server managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. If a matching container is found, it is used, and so a second one is not started. Otherwise, Dev Services for Unleash starts a new container.

The discovery uses the quarkus-dev-service-unleash label. The value is configured using the service-name property.

Container sharing is only used in dev mode.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_SHARED

boolean

true

The value of the quarkus-dev-service-unleash label attached to the started container. This property is used when shared is set to true. In this case, before starting a container, Dev Services for Unleash looks for a container with the quarkus-dev-service-unleash label set to the configured value. If found, it will use this container instead of starting a new one. Otherwise, it starts a new container with the quarkus-dev-service-unleash label set to the specified value.

This property is used when you need multiple shared Unleash servers.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_SERVICE_NAME

string

unleash

The container image name to use, for container based DevServices providers.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_IMAGE_NAME

string

Enabled or disable log of the mock-server

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_LOG

boolean

false

Helper to define the stop strategy for containers created by DevServices. In particular, we don’t want to actually stop the containers when they have been flagged for reuse, and when the Testcontainers configuration has been explicitly set to allow container reuse. To enable reuse, ass testcontainers.reuse.enable=true in your .testcontainers.properties file, to be stored in your home.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_REUSE

boolean

false

The import data from file during the start.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_IMPORT_FILE

string

The container image name to use, for unleash database.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_DB_IMAGE_NAME

string

postgres:15.2

The value of the quarkus-dev-service-unleash-db label attached to the started container. This property is used when shared is set to true. In this case, before starting a container, Dev Services for Unleash DB looks for a container with the quarkus-dev-service-unleash-db label set to the configured value. If found, it will use this container instead of starting a new one. Otherwise, it starts a new container with the quarkus-dev-service-unleash-db label set to the specified value.

This property is used when you need multiple shared Unleash DB servers.

Environment variable: QUARKUS_UNLEASH_DEVSERVICES_DB_SERVICE_NAME

string

unleash-db

Whether or not the Unleash extension is active.

Environment variable: QUARKUS_UNLEASH_ACTIVE

boolean

true

Unleash URL service endpoint

Environment variable: QUARKUS_UNLEASH_URL

string

required

Application name

Environment variable: QUARKUS_UNLEASH_APPLICATION

string

Project name

Environment variable: QUARKUS_UNLEASH_PROJECT

string

Instance ID.

Environment variable: QUARKUS_UNLEASH_INSTANCE_ID

string

Disable Unleash metrics

Environment variable: QUARKUS_UNLEASH_DISABLE_METRICS

boolean

false

Application Unleash token

Environment variable: QUARKUS_UNLEASH_TOKEN

string

Application environment

Environment variable: QUARKUS_UNLEASH_ENVIRONMENT

string

Fetch toggles interval (in seconds)

Environment variable: QUARKUS_UNLEASH_FETCH_TOGGLES_INTERVAL

long

10

Send metrics interval (in seconds)

Environment variable: QUARKUS_UNLEASH_SEND_METRICS_INTERVAL

long

60

Backup file

Environment variable: QUARKUS_UNLEASH_BACKUP_FILE

string

A synchronous fetch on initialisation

Environment variable: QUARKUS_UNLEASH_SYNCHRONOUS_FETCH_ON_INITIALISATION

boolean

false

Enable proxy authentication by JVM properties

Environment variable: QUARKUS_UNLEASH_ENABLE_PROXY_AUTHENTICATION_BY_JVM_PROPERTIES

boolean

false

If provided, the Unleash client will only fetch toggles whose name starts with the provided value.

Environment variable: QUARKUS_UNLEASH_NAME_PREFIX

string