This project demonstrates how to use Redis Pub/Sub to synchronize feature flag states across multiple instances of a Spring Boot application.
It showcases how Redis can act as a real-time event broadcaster rather than just a caching layer or data store.
The application manages a set of feature flags stored in a database.
Each application instance keeps its own local in-memory cache (syncronized map) that holds the enabled/disabled state of every feature.
When a feature flag is updated through the API:
- The change is persisted to the database.
- A message is published to a Redis channel.
- All instances subscribed to that channel automatically update their local cache.
This approach achieves real-time synchronization across distributed application instances without requiring a shared cache lookup on every request.
Traditionally, applications fetch feature flags from Redis or a database on each request or periodically poll for updates.
While simple, this introduces several drawbacks:
| Problem | Typical Approach | This Project’s Approach |
|---|---|---|
| Latency | Each request hits Redis/DB | Only the initial load; updates are pushed instantly |
| Network overhead | High (every request = network round-trip) | Minimal (publish only on change) |
| Consistency | Polling causes delayed sync | Pub/Sub ensures near real-time sync |
| Memory | Low, but with high latency | Slightly higher memory, but negligible (<1 MB for thousands of flags) |
In this project:
- Each instance holds a synchronized map of feature states.
- Redis is only used as a notification channel — not as a data store.
- When a flag is updated, all instances are notified instantly via Pub/Sub.
This eliminates the need for constant lookups, reducing latency and network load while maintaining consistency across all nodes.
- Java 21
- Spring Boot 3.x
- Spring Data JPA
- Redis Pub/Sub
- MySQL (for the feature flag table)
- Traefik (for load balancing)
- Docker Compose
Table: feature_flag
| Column | Type | Description |
|---|---|---|
feature_type |
VARCHAR | Enum value (e.g. FEATURE_1, FEATURE_2) |
enabled |
BOOLEAN | Whether the feature is enabled or not |
The project includes a Docker Compose setup with the following services:
- redis — Redis server used for Pub/Sub messaging
- mysql — MySQL database for feature flag persistence
- redis-pub-sub — The Spring Boot application (scalable service)
- traefik — Reverse proxy and load balancer
docker compose up -dYou can simulate multiple instances with a single command:
docker compose up --scale redis-pub-sub=3 -dTraefik automatically load balances incoming requests between all instances.
Traefik exposes the application via port 80:
http://localhost/api/features| Method | Endpoint | Description |
|---|---|---|
GET |
/api/features/{type} |
Returns the current feature flag state |
PATCH |
/api/features/{type} |
Updates the feature flag and publishes a Redis event |
Example
curl -X PATCH "http://localhost:8080/api/features/FEATURE_1" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'- On startup, each redis-pub-sub instance loads all feature flags from MySQL into a local synchronized map.
- When a flag is updated via the PATCH API:
- The database record is updated.
- A message is published to the Redis channel (e.g. feature_flag_updates).
- All instances subscribed to that channel receive the event.
- Each updates its in-memory map and logs the change.
Example log output:
redis-pub-sub-3 | [FEATURE_FLAG_SUSCRIBER] [MESSAGE] [FEATURE=FEATURE_1] [ENABLED=true]
redis-pub-sub-2 | [FEATURE_FLAG_SUSCRIBER] [MESSAGE] [FEATURE=FEATURE_1] [ENABLED=true]
redis-pub-sub-1 | [FEATURE_FLAG_SUSCRIBER] [MESSAGE] [FEATURE=FEATURE_1] [ENABLED=true]| Class | Description |
|---|---|
FeatureFlag |
Entity representing a feature flag record |
FeatureType |
Enum for all feature names |
FeatureFlagService |
Managing CRUD operations and in memory cache |
FeatureFlagSubscriber |
Listens for Redis messages and updates local cache via FeatureFlagService |
FeatureFlagController |
Exposes REST endpoints for managing feature flags |
You can read a detailed explanation of this project and the Redis Pub/Sub in the blog post here:
👉 Read the Blog Post
Contributions are welcome! Feel free to fork the repo, submit pull requests or open issues.
This project is licensed under the MIT License.