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 |
@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: |
boolean |
|
Optional fixed port the dev service will listen to. If not defined, the port will be chosen randomly. Environment variable: |
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 Container sharing is only used in dev mode. Environment variable: |
boolean |
|
The value of the This property is used when you need multiple shared Unleash servers. Environment variable: |
string |
|
The container image name to use, for container based DevServices providers. Environment variable: |
string |
|
Enabled or disable log of the mock-server Environment variable: |
boolean |
|
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 Environment variable: |
boolean |
|
The import data from file during the start. Environment variable: |
string |
|
The container image name to use, for unleash database. Environment variable: |
string |
|
The value of the This property is used when you need multiple shared Unleash DB servers. Environment variable: |
string |
|
Whether or not the Unleash extension is active. Environment variable: |
boolean |
|
Unleash URL service endpoint Environment variable: |
string |
required |
Application name Environment variable: |
string |
|
Project name Environment variable: |
string |
|
Instance ID. Environment variable: |
string |
|
Disable Unleash metrics Environment variable: |
boolean |
|
Application Unleash token Environment variable: |
string |
|
Application environment Environment variable: |
string |
|
Fetch toggles interval (in seconds) Environment variable: |
long |
|
Send metrics interval (in seconds) Environment variable: |
long |
|
Backup file Environment variable: |
string |
|
A synchronous fetch on initialisation Environment variable: |
boolean |
|
Enable proxy authentication by JVM properties Environment variable: |
boolean |
|
If provided, the Unleash client will only fetch toggles whose name starts with the provided value. Environment variable: |
string |