Skip to content

Comments

Feat/data storage layer #31

Open
akintewe wants to merge 2 commits intoNeko-Protocol:mainfrom
akintewe:feat/data-storage-layer-20
Open

Feat/data storage layer #31
akintewe wants to merge 2 commits intoNeko-Protocol:mainfrom
akintewe:feat/data-storage-layer-20

Conversation

@akintewe
Copy link

feat(aggregator): implement Redis-backed Data Storage Layer

Summary

  • Implements a StorageService backed by Redis (ioredis) to persist aggregated prices with configurable TTL
  • Maintains per-symbol price history as a time-series using Redis Sorted Sets
  • Exposes batch read/write operations for the API service to query efficiently
  • Degrades gracefully to no-op mode when REDIS_URL is not configured — the service starts cleanly and aggregation is never interrupted
  • Adds 3 new Prometheus metrics for cache hits, misses, and operation duration
  • 52 unit tests with mocked ioredis achieving >95% line coverage on StorageService
  • Adds docker-compose.yml at the project root with a Redis 7.2-alpine service
  • Also fixes a pre-existing build error in the ingestor service (missing SchedulerService import)

Redis Key Schema

Key Pattern Type TTL Purpose
price:latest:{SYMBOL} STRING (JSON) REDIS_PRICE_TTL_SECONDS (default 300 s) Latest aggregated price per symbol
price:history:{SYMBOL} SORTED SET (score = computedAt ms) None (bounded by trim) Time-series history per symbol
price:symbols SET None Index of all tracked symbols

New Environment Variables

Variable Default Description
REDIS_URL (unset) Redis connection URL. When absent, service runs in no-op mode.
REDIS_PRICE_TTL_SECONDS 300 TTL for latest price key in seconds (5 min default)
REDIS_HISTORY_MAX_ENTRIES 100 Max history entries kept per symbol
REDIS_KEY_PREFIX price Key namespace prefix (useful for shared Redis instances)

Files Changed

New Files

  • apps/aggregator/src/services/storage.service.ts — Core Redis service with 9 public methods
  • apps/aggregator/src/services/storage.service.spec.ts — 52 unit tests (>95% line coverage)
  • apps/aggregator/src/modules/storage.module.ts — NestJS feature module
  • apps/aggregator/src/interfaces/storage-options.interface.ts — Typed options interfaces
  • apps/aggregator/src/config/redis.config.ts — ConfigFactory for Redis env vars
  • docker-compose.yml — Redis 7.2-alpine with health check and LRU eviction policy

Modified Files

  • apps/aggregator/src/services/aggregation.service.ts — Injects StorageService @Optional(), calls storePrice fire-and-forget after each aggregation
  • apps/aggregator/src/metrics/metrics.service.ts — Adds storageCacheHits, storageCacheMisses, storageOperationDuration Prometheus instruments
  • apps/aggregator/src/app.module.ts — Registers StorageModule; also fixes pre-existing bugs (missing HttpModule/EventEmitterModule imports, duplicate ConfigModule.forRoot)
  • apps/aggregator/package.json — Removes duplicate axios entry
  • apps/aggregator/.env.example — Documents all 4 REDIS_* environment variables
  • apps/aggregator/README.md — Adds Redis Storage section with schema, env vars, metrics, and graceful degradation docs
  • apps/ingestor/src/modules/prices.module.ts — Fixes missing SchedulerService import (pre-existing build error)

How to Test

# Start Redis
docker compose up -d redis

# Configure
echo "REDIS_URL=redis://localhost:6379" >> apps/aggregator/.env

# Run the service
cd apps/aggregator && npm run start:dev

# Health check (Redis should show "up")
curl http://localhost:3001/health

# Storage metrics visible at
curl http://localhost:3001/metrics | grep aggregator_storage

# Run unit tests
cd apps/aggregator && npm test -- --coverage

Closes #20

…tocol#20)

Add StorageService with ioredis to persist aggregated prices with TTL,
maintain per-symbol time-series history via Sorted Sets, and expose
batch read/write operations for the API service.

- StorageService: storePrice, getLatestPrice, getPriceHistory,
  storePriceBatch, getLatestPriceBatch, getTrackedSymbols, deleteSymbol
- Redis key schema: latest (STRING+TTL), history (ZSET), symbols (SET)
- Auto-reconnection via ioredis retryStrategy (exponential back-off)
- No-op mode when REDIS_URL is unset — service starts cleanly
- StorageModule (NestJS feature module) + storage-options.interface.ts
- redis.config.ts ConfigFactory for REDIS_* env vars
- 3 new Prometheus metrics: cache hits/misses + operation duration
- AggregationService wired to fire-and-forget storePrice on each aggregation
- 52 unit tests with mocked ioredis (>95% line coverage)
- docker-compose.yml with Redis 7.2-alpine, LRU eviction, health check
- Fix app.module.ts: missing HttpModule/EventEmitterModule imports,
  duplicate ConfigModule.forRoot, remove duplicate axios in package.json
- README: Redis Storage section with key schema, env vars, metrics table
SchedulerService was used in providers and exports but not imported,
causing a TypeScript compile error that was already present on main.
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.

Data Storage Layer

1 participant