Skip to content

Feature/redis infrastructure#26

Merged
tsekovTriesCoding merged 2 commits intomainfrom
feature/redis-infrastructure
Mar 14, 2026
Merged

Feature/redis infrastructure#26
tsekovTriesCoding merged 2 commits intomainfrom
feature/redis-infrastructure

Conversation

@tsekovTriesCoding
Copy link
Owner

@tsekovTriesCoding tsekovTriesCoding commented Mar 14, 2026

What's New

1. Session Caching (auth-service)

  • Cache /auth/me responses in Redis for 15 minutes via UserSessionCacheService
  • Evicted on logout, account suspension, or status change
  • Eliminates a DB query + REST call to user-service on every page navigation

2. Token Blocklist (auth-service)

  • TokenBlocklistService blocks revoked access tokens in Redis with TTL matching token remaining lifetime
  • Checked in AuthController.getCurrentUser() before serving /auth/me
  • Fail-open on Redis unavailability (graceful degradation)

3. Rate Limiting (api-gateway)

  • RateLimitFilter uses a Redis Lua script for atomic sliding-window rate limiting
  • Tiered limits: auth endpoints (20/min), admin (200/min), default (100/min)
  • Configurable via RateLimitProperties in application.yaml
  • Fail-open: if Redis is down, requests pass through

4. Idempotency Deduplication (finpay-outbox-starter)

  • RedisIdempotentConsumerService accelerates duplicate event detection using Redis before DB lookup
  • Write-through pattern: DB first, then Redis cache
  • Auto-configured via @ConditionalOnBean(StringRedisTemplate); falls back to DB-only without Redis
  • Backfills Redis on DB hit for self-healing cache

5. Wallet & Analytics Caching (wallet-service)

  • WalletCacheService: caches wallet reads for 10 seconds, evicted on any wallet mutation (deposit, withdraw, transfer, freeze, unfreeze)
  • WalletAnalyticsCacheService: caches admin dashboard metrics for 30 seconds

6. Secure Refresh Token Storage (auth-service)

  • Breaking change: removed raw token column from refresh_tokens table
  • Only the SHA-256 hash (tokenHash, 64-char hex) is persisted - raw token is never stored
  • Lookups via findByTokenHash() after hashing the incoming token
  • Extracted sha256() to TokenHashUtil utility class (clean entity, no crypto in JPA model)
  • Follows the same pattern used by GitHub, Stripe, and Laravel Sanctum

Resilience

  • All Redis operations wrapped in try-catch with graceful degradation
  • Every cache/blocklist service logs warnings on Redis failure and continues without crashing
  • Rate limiter fails open - no Redis means no rate limiting, not a 500

Infrastructure

  • Redis 7 Alpine added to docker-compose.yml (256MB, allkeys-lru eviction)
  • spring-boot-starter-data-redis added to parent POM
  • StringRedisTemplate used everywhere (auto-configured by Spring Boot, no custom RedisConfig)

Testing

  • Redis Testcontainers (redis:7-alpine) added to all 5 service TestcontainersConfig files
  • New unit tests: TokenBlocklistServiceTest, UserSessionCacheServiceTest, RateLimitFilterTest, RedisIdempotentConsumerServiceTest
  • All existing tests updated for tokenHash changes
  • All 8 services pass: 118 (auth) + all others green

Commits:

  • 704b600 feat: add Redis infrastructure for caching, rate limiting, and idempotency
  • 84282df refactor: store only SHA-256 hash of refresh tokens

…tency

Add Redis 7 (Alpine) as a distributed cache layer across the platform,
using Spring Boot auto-configured StringRedisTemplate throughout.

Session caching (auth-service):
- TokenBlocklistService: Redis-backed token revocation with TTL matching
  token lifetime, fail-open on Redis unavailability
- UserSessionCacheService: cache /auth/me responses (15min TTL),
  evicted on logout, status change, and profile update via Kafka events
- Integrate blocklist check into AuthService.logout() and session
  caching into AuthController.getCurrentUser()

Rate limiting (api-gateway):
- RateLimitFilter: Redis-backed sliding-window rate limiter using
  Lua script (sorted set) for atomic increment + check
- Tiered limits: auth (20/min), admin (200/min), default (100/min)
- Configurable via RateLimitProperties, fail-open when Redis is down
- Client key derived from X-User-Id header or client IP

Idempotency deduplication (finpay-outbox-starter):
- RedisIdempotentConsumerService: Redis-accelerated duplicate check
  with automatic DB fallback (sub-ms fast path, DB slow path)
- Write-through pattern: DB first (source of truth), then Redis with TTL
- Smart backfill: cache-warm Redis on DB hit for future lookups
- Auto-configured via @ConditionalOnBean(StringRedisTemplate),
  falls back to DB-only IdempotentConsumerService without Redis

Analytics caching (wallet-service):
- WalletCacheService: cache wallet read responses (10s TTL),
  evicted on every write operation (deposit, withdraw, freeze, etc.)
- WalletAnalyticsCacheService: cache admin dashboard metrics (30s TTL),
  evicted on wallet mutations

Infrastructure:
- Redis 7 Alpine in docker-compose.yml (maxmemory 256mb, allkeys-lru)
- spring-boot-starter-data-redis added to all service POMs
- testcontainers-redis (com.redis:testcontainers-redis:2.2.4) for
  integration tests with @Serviceconnection
- Redis testcontainer added to all 5 TestcontainersConfig files
- All Redis operations wrapped in try-catch with graceful degradation

Tests:
- TokenBlocklistServiceTest (6 tests)
- UserSessionCacheServiceTest (4 tests)
- RateLimitFilterTest (6 tests)
- RedisIdempotentConsumerServiceTest (8 tests)
- All use @InjectMocks/@SPY (no new keyword anti-pattern)
- Fixed existing tests: added missing @mock for new dependencies,
  cache eviction in @beforeeach for test isolation
- Remove raw token column from RefreshToken entity (security best practice)
- Add tokenHash column (64-char SHA-256 hex, unique indexed)
- Extract sha256() from entity to TokenHashUtil utility class
- Update AuthService and OAuth2SuccessHandler to hash before persisting
- Update RefreshTokenRepository to findByTokenHash
- Update all tests (unit, integration, repository)
@tsekovTriesCoding tsekovTriesCoding merged commit 37b603b into main Mar 14, 2026
3 checks passed
@tsekovTriesCoding tsekovTriesCoding deleted the feature/redis-infrastructure branch March 14, 2026 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant