Skip to content

Commit e9ed0f2

Browse files
authored
[FSSDK-12072] Integrate Redis Streams into agent (#448)
* Integrate Redis Streams and enhance CMAB with flexible authentication This commit integrates Redis Streams for persistent notification delivery from v4.3.0-beta.1 with the existing CMAB Redis cache support in master. Features Added: - Redis Streams implementation for notification synchronization with persistent message delivery, automatic retries, consumer groups, and configurable batching - Flexible Redis authentication utility supporting auth_token, redis_secret, and password fields with environment variable fallback - Applied flexible auth pattern to all Redis clients: ODP cache, UPS, CMAB cache, and synchronization pubsub - Configurable CMAB prediction endpoint via config or environment variable Changes: - Added pkg/syncer/pubsub/redis_streams.go and comprehensive tests - Added pkg/utils/redisauth for flexible password authentication - Updated all Redis clients (ODP, UPS, CMAB) with UnmarshalJSON for auth - Updated config.yaml with Redis Streams parameters and auth_token field - Updated CHANGELOG.md with [Unreleased] section documenting new features - Updated CI workflow to use Redis 6 and added Redis to test-coverage job - Added docs/redis-streams.md with complete Redis Streams documentation Configuration: - CMAB configuration remains under client.cmab section - Redis Streams enabled via synchronization.notification.default - All Redis clients support auth_token, redis_secret, password fields - Environment variables: REDIS_PASSWORD, REDIS_ODP_PASSWORD, REDIS_UPS_PASSWORD, REDIS_CMAB_PASSWORD Testing: - All existing tests pass - Added 5 new auth tests for CMAB Redis cache - Redis Streams includes 18 comprehensive tests - redisauth utility includes 14 tests covering all scenarios Both features coexist without conflicts - Redis Streams uses STREAM data type for messaging while CMAB cache uses STRING type for key-value storage. * add autodetection of redis version * fix alias * Removed force_implementation config field and comments about manual override * cleanup * improve test coverage * Add SSE timeout warning to config and reset notification sync to default
1 parent 6632f73 commit e9ed0f2

24 files changed

Lines changed: 4541 additions & 73 deletions

.github/workflows/agent.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ jobs:
5050
with:
5151
go-version: '1.24.0'
5252
check-latest: true
53+
- name: Start Redis
54+
uses: supercharge/redis-github-action@1.5.0
55+
with:
56+
redis-version: 5
5357
- name: coveralls
5458
id: coveralls
5559
run: |
@@ -111,7 +115,7 @@ jobs:
111115
- name: Start Redis
112116
uses: supercharge/redis-github-action@1.5.0
113117
with:
114-
redis-version: 4
118+
redis-version: 5
115119
- name: acceptance test
116120
run: |
117121
make -e setup build

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,43 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## [Unreleased]
8+
9+
### New Features
10+
11+
* **Redis Streams for Persistent Notification Delivery**: Added Redis Streams implementation as an alternative to Redis Pub/Sub for notification synchronization across Agent nodes. Redis Streams provides:
12+
- Persistent message delivery with acknowledgment
13+
- Automatic retries with exponential backoff
14+
- Consumer groups for load balancing
15+
- Configurable batching and flush intervals
16+
- Connection error recovery with reconnection logic
17+
- Comprehensive metrics tracking
18+
19+
Configure via `synchronization.notification.default: "redis-streams"` in config.yaml. See [docs/redis-streams.md](docs/redis-streams.md) for configuration options including batch_size, flush_interval, max_retries, and connection_timeout.
20+
21+
* **CMAB Redis Cache Support** ([#447](https://github.com/optimizely/agent/pull/447)): Added Redis cache support for Contextual Multi-Armed Bandit (CMAB) decisions following the same plugin-based architecture as ODP cache:
22+
- In-memory LRU cache (default, size: 10000, TTL: 30m)
23+
- Redis cache for multi-instance deployments with shared caching
24+
- Configurable via `client.cmab.cache` in config.yaml
25+
- Supports both in-memory and Redis cache backends
26+
27+
* **Flexible Redis Authentication**: Added support for flexible Redis password field names across all Redis clients (ODP cache, UPS, CMAB cache, and synchronization):
28+
- Supports `auth_token`, `redis_secret`, and `password` fields (in order of preference)
29+
- Falls back to environment variables: `REDIS_PASSWORD`, `REDIS_ODP_PASSWORD`, `REDIS_UPS_PASSWORD`, `REDIS_CMAB_PASSWORD`
30+
- Avoids security scanning alerts from hardcoded "password" field names
31+
32+
* **CMAB Prediction Endpoint Configuration**: Added configurable CMAB prediction endpoint via `client.cmab.predictionEndpoint` in config.yaml or `OPTIMIZELY_CMAB_PREDICTIONENDPOINT` environment variable for testing/staging environments
33+
34+
### Changed
35+
36+
* Updated Redis configuration in `synchronization.pubsub.redis` to use `auth_token` instead of `password` field (backwards compatible)
37+
* CMAB configuration moved from top-level to `client.cmab` section for consistency with other client-related settings (ODP, UPS)
38+
39+
### Fixed
40+
41+
* Improved Redis connection error handling and recovery across all Redis clients
42+
* Added comprehensive test coverage for Redis authentication and CMAB caching
43+
744
## [4.2.2] - October 7, 2025
845

946
### Fixed

config.yaml

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ server:
8080
## Note: don't include port in these hosts values - port is stripped from the request host before comparing against these.
8181
allowedHosts:
8282
- localhost
83+
84+
## If using notifications API (/v1/notifications/event-stream),
85+
## increase these timeouts to prevent SSE disconnects.
8386
## the maximum duration for reading the entire request, including the body.
8487
## Value can be set in seconds (e.g. "5s") or milliseconds (e.g. "5000ms")
8588
readTimeout: 5s
@@ -285,20 +288,37 @@ runtime:
285288
synchronization:
286289
pubsub:
287290
redis:
288-
host: "redis.demo.svc:6379"
289-
password: ""
291+
host: "localhost:6379"
292+
## Use auth_token or redis_secret instead of password to avoid security scanning alerts
293+
## Supports: auth_token, redis_secret, password (in order of preference)
294+
## Fallback: REDIS_PASSWORD environment variable if config field is empty
295+
auth_token: ""
290296
database: 0
291-
## channel: "optimizely-sync" # Base channel name (NOT currently parsed - uses hardcoded default)
292-
## Agent publishes to channels: "optimizely-sync-{sdk_key}"
293-
## For external Redis clients: Subscribe "optimizely-sync-{sdk_key}" or PSubscribe "optimizely-sync-*"
294-
## Note: Channel configuration parsing is a known bug - planned for future release
297+
298+
## Advanced: Redis Streams Configuration (auto-detected, optional tuning)
299+
## Agent automatically detects Redis version:
300+
## - Redis >= 5.0: Uses Redis Streams (persistent, batched delivery)
301+
## - Redis < 5.0: Uses Redis Pub/Sub (simple, fire-and-forget)
302+
##
303+
## The parameters below only apply when Redis Streams is used (Redis >= 5.0).
304+
## Uncomment to override defaults. Leave commented to use defaults.
305+
# batch_size: 10 # Messages per batch (default: 10)
306+
# flush_interval: 5s # Max wait before sending batch (default: 5s)
307+
# max_retries: 3 # Retry attempts on failure (default: 3)
308+
# retry_delay: 100ms # Initial retry delay (default: 100ms)
309+
# max_retry_delay: 5s # Max retry delay with backoff (default: 5s)
310+
# connection_timeout: 10s # Redis connection timeout (default: 10s)
311+
295312
## if notification synchronization is enabled, then the active notification event-stream API
296313
## will get the notifications from available replicas
297314
notification:
298315
enable: false
316+
## Agent auto-detects best option based on Redis version
299317
default: "redis"
318+
300319
## if datafile synchronization is enabled, then for each webhook API call
301320
## the datafile will be sent to all available replicas to achieve better eventual consistency
302321
datafile:
303322
enable: false
323+
## Agent auto-detects best option based on Redis version
304324
default: "redis"

config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func NewDefaultConfig() *AgentConfig {
103103
},
104104
},
105105
CMAB: CMABConfig{
106-
RequestTimeout: 10 * time.Second,
106+
RequestTimeout: 10 * time.Second,
107107
PredictionEndpoint: "https://prediction.cmab.optimizely.com/predict/%s",
108108
Cache: CMABCacheConfig{
109109
"default": "in-memory",

0 commit comments

Comments
 (0)