How to configure a self-made jar to enable/disable toggles created using feature flags on Gitlab?

I currently have 2 components in my project, one is a JAR which we have constructed for our specific needs, the other is an application which uses our JAR to run it, the issue we are facing now is that the application has been pushed onto GitLab and we have created feature flags for the application to enable/disable some features, but our requirement is that we need to do some configuration in our JAR and the build it so that other applications can also use our JAR for enabling/disabling those features using feature flags in their own GitLab? We are using Unleash for it but it doesn’t seem to be working out, does anyone have any suggestions or any idea on how Unleash can be correctly used to make it work out?

  1. Have an Unleash Configuration class in JAR which reads the properties from the application for specific Gitlab API URL, Instance ID and Application name.
  2. This class creates a bean after reading the properties but it gives errors, the configuration doesn’t seem to happen even with correct dependencies and build.

To solve the issue with your JAR and its integration with feature flags via Unleash, let’s break this down systematically:


1. Problem Analysis

  • JAR’s Purpose: It contains an Unleash configuration class meant to initialize feature flagging by reading properties (GitLab API URL, Instance ID, Application Name) from the consuming application’s configuration.
  • Issue: The configuration in the JAR does not seem to work properly when integrated into applications, even with correct dependencies and build setup.

2. Key Factors to Validate

A. Dependencies

Ensure the JAR includes all necessary dependencies for Unleash in its pom.xml (or build file). Common issues arise if the consuming application does not include some transitive dependencies. Verify:

<dependency>
    <groupId>no.finn.unleash</groupId>
    <artifactId>unleash-client-java</artifactId>
    <version>5.1.0</version> <!-- Update based on the latest version -->
</dependency>

If your JAR does not package these dependencies, consider using a fat JAR (via plugins like Maven’s shade plugin or Gradle’s shadow plugin).


B. Configuration Source

Your configuration class in the JAR should:

  1. Be able to dynamically read configurations from the consuming application.
  2. Handle the absence of specific configurations gracefully (e.g., provide meaningful logs or defaults).

Example configuration class for Unleash:

import no.finn.unleash.DefaultUnleash;
import no.finn.unleash.util.UnleashConfig;

@Configuration
public class UnleashConfigClass {
    
    @Bean
    public DefaultUnleash unleash(@Value("${unleash.api.url}") String apiUrl,
                                   @Value("${unleash.instance.id}") String instanceId,
                                   @Value("${unleash.app.name}") String appName) {
        UnleashConfig config = UnleashConfig.builder()
                .appName(appName)
                .instanceId(instanceId)
                .unleashAPI(apiUrl)
                .build();

        return new DefaultUnleash(config);
    }
}
  • Ensure the consuming application provides these properties via its configuration files (e.g., application.properties, application.yml).

Example application.properties:

unleash.api.url=https://gitlab.yourdomain.com/api/feature-flags
unleash.instance.id=your-instance-id
unleash.app.name=your-app-name

C. Testing the JAR

  • Test the JAR in isolation with mock properties before integrating it into the consuming application.
  • Include logging in your configuration class to confirm the properties are being read correctly:
log.info("Initializing Unleash with API URL: {}", apiUrl);
log.info("Instance ID: {}, App Name: {}", instanceId, appName);

3. Consuming Application: Best Practices

  • Ensure the Spring Context (if using Spring) can detect and use the JAR’s beans. Use annotations like @ComponentScan if necessary:
@SpringBootApplication(scanBasePackages = {"your.package.in.jar"})
public class Application {}
  • Validate the Unleash client is being initialized correctly in the consuming application. Add a test bean:
@Autowired
private DefaultUnleash unleash;

@PostConstruct
public void testFeatureFlags() {
    log.info("Feature flag test: {}", unleash.isEnabled("some-feature-flag"));
}

4. Using Unleash for Feature Flags

  • Unleash is designed to decouple feature flagging logic from application code. Ensure:
    • Separate Control: Feature flags and logic should not depend on the JAR. The consuming application must provide feature flag keys and manage them independently.
    • Dynamic Features: The JAR can expose a utility/service that consuming applications use to query feature flags.

Example Utility in JAR:

public class FeatureFlagService {
    private final DefaultUnleash unleash;

    public FeatureFlagService(DefaultUnleash unleash) {
        this.unleash = unleash;
    }

    public boolean isFeatureEnabled(String featureName) {
        return unleash.isEnabled(featureName);
    }
}

The consuming application can then use:

@Autowired
private FeatureFlagService featureFlagService;

public void someMethod() {
    if (featureFlagService.isFeatureEnabled("some-feature")) {
        // Feature-specific logic
    }
}

5. Debugging Common Issues

  • Error: Missing Dependencies:
    • Ensure all required libraries (e.g., unleash-client-java) are present in the classpath of both the JAR and the consuming application.
  • Error: Properties Not Read:
    • Add fallback configurations in your JAR if the consuming application fails to provide them:
String apiUrl = Optional.ofNullable(env.getProperty("unleash.api.url")).orElse("default-url");
  • Error: Instance Overlap in GitLab:
    • Each application must have a unique Instance ID. Ensure the consuming application sets its instance in the properties.

6. Alternative Approaches

If Unleash continues to present challenges, consider alternatives:

  1. Spring Profiles: Use Spring’s built-in @Profile to toggle features based on configuration.
  2. Togglz: A lightweight feature flagging library that works well with Spring.
  3. Custom Properties: For simpler use cases, manage feature toggles through application.properties or a central config server.

Next Steps

  • Refactor your JAR’s configuration class to dynamically read properties.
  • Ensure clear separation of feature flag logic between the JAR and the consuming application.
  • Test the JAR independently and log property values to confirm proper configuration.
  • Integrate into a sample consuming application and test feature flags.

Let me know if you encounter specific errors or issues during testing, and I’ll assist further!