From d5e907d7cc8cfba5e54edfa8fd11a5506f7d539c Mon Sep 17 00:00:00 2001 From: BrewingCoder Date: Sat, 9 May 2026 09:55:27 -0400 Subject: [PATCH] =?UTF-8?q?infra:=20drop=20redis=20container=20=E2=80=94?= =?UTF-8?q?=20RedisService=20was=20unused=20(HOL-22)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RedisService was registered in DI as a singleton but no code path actually injected it. Pure dead infrastructure carrying its own container, network port, persistent volume, and StackExchange.Redis package dependency. Removed: - src/dotnet/src/HoldFast.Shared/Redis/{RedisService, RedisOptions} - src/dotnet/tests/HoldFast.Shared.Tests/Redis/ - HoldFast.Shared.csproj: StackExchange.Redis package reference - Program.cs: Redis DI registration + using - compose.yml: redis service + redis-data volume - compose.hobby-dotnet.yml: Redis__Configuration env mapping - .env.example: REDIS_IMAGE_NAME, REDIS_PASSWORD - env.sh: REDIS_EVENTS_STAGING_ENDPOINT exports If a future code path actually needs caching, IMemoryCache (in-process) covers self-hosted scale; users at multi-node scale can re-add Redis explicitly. Verified: docker compose ps now shows 6 HoldFast containers (was 7 after HOL-21). Smoke test passes end-to-end. Stacks on HOL-21. Subtask of HOL-17. Closes HOL-22. Co-Authored-By: Claude Opus 4.7 --- infra/docker/.env.example | 3 +- infra/docker/compose.hobby-dotnet.yml | 1 - infra/docker/compose.yml | 19 +---- infra/docker/env.sh | 2 - src/dotnet/src/HoldFast.Api/Program.cs | 6 -- .../HoldFast.Shared/HoldFast.Shared.csproj | 1 - .../src/HoldFast.Shared/Redis/RedisService.cs | 71 ------------------- .../Redis/RedisOptionsTests.cs | 64 ----------------- 8 files changed, 4 insertions(+), 163 deletions(-) delete mode 100644 src/dotnet/src/HoldFast.Shared/Redis/RedisService.cs delete mode 100644 src/dotnet/tests/HoldFast.Shared.Tests/Redis/RedisOptionsTests.cs diff --git a/infra/docker/.env.example b/infra/docker/.env.example index db882e16..b802cd92 100644 --- a/infra/docker/.env.example +++ b/infra/docker/.env.example @@ -24,7 +24,6 @@ KAFKA_IMAGE_NAME=confluentinc/cp-kafka:7.7.0 POSTGRES_IMAGE_NAME=ankane/pgvector:v0.5.1 # OTEL collector image vars removed — HOL-21 dropped the collector container. # Backend hosts the OTLP receiver at /otel/v1/{logs,traces,metrics}. -REDIS_IMAGE_NAME=redis:8.0.2 ZOOKEEPER_IMAGE_NAME=confluentinc/cp-zookeeper:7.7.0 # ── ClickHouse (analytics) ────────────────────────────────────────── @@ -45,7 +44,7 @@ KAFKA_SERVERS=kafka:9092 KAFKA_TOPIC=dev # ── Redis ─────────────────────────────────────────────────────────── -REDIS_PASSWORD=redispassword +# Removed in HOL-22 — backend uses IMemoryCache + Postgres instead. # ── Frontend / API URLs ───────────────────────────────────────────── REACT_APP_DISABLE_ANALYTICS=false diff --git a/infra/docker/compose.hobby-dotnet.yml b/infra/docker/compose.hobby-dotnet.yml index ac4592fd..9f9b7986 100644 --- a/infra/docker/compose.hobby-dotnet.yml +++ b/infra/docker/compose.hobby-dotnet.yml @@ -21,7 +21,6 @@ services: - ClickHouse__Password=${CLICKHOUSE_PASSWORD:-} - ClickHouse__Migrations__Path=/app/clickhouse-migrations - ClickHouse__Migrations__Disabled=${CLICKHOUSE_MIGRATIONS_DISABLED:-false} - - Redis__Configuration=${REDIS_ADDRESS:-redis:6379} - Kafka__BootstrapServers=${KAFKA_SERVERS:-kafka:9092} - Storage__Type=filesystem - Storage__FilesystemRoot=/highlight-data diff --git a/infra/docker/compose.yml b/infra/docker/compose.yml index 9a460161..958542b2 100644 --- a/infra/docker/compose.yml +++ b/infra/docker/compose.yml @@ -41,21 +41,9 @@ services: KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' - redis: - logging: *local-logging - container_name: redis - image: ${REDIS_IMAGE_NAME} - restart: on-failure - environment: - REDIS_PASSWORD: ${REDIS_PASSWORD} - volumes: - - redis-data:/data - ports: - - '0.0.0.0:6379:6379' - command: - - redis-server - - --save 60 1 - - --loglevel warning + # Redis removed in HOL-22 — RedisService was registered in DI but no + # code path actually injected it. Self-hosted scale doesn't need a + # separate cache layer; .NET's IMemoryCache + Postgres cover it. postgres: logging: *local-logging @@ -100,7 +88,6 @@ volumes: postgres-data: clickhouse-data: clickhouse-logs: - redis-data: kafka-data: zoo-log: zoo-data: diff --git a/infra/docker/env.sh b/infra/docker/env.sh index 2cce548e..25766697 100644 --- a/infra/docker/env.sh +++ b/infra/docker/env.sh @@ -33,7 +33,6 @@ if [[ "$*" == *"--go-docker"* ]]; then export OTLP_DOGFOOD_ENDPOINT=http://backend:8082/otel export OTLP_ENDPOINT=http://backend:8082/otel export PSQL_HOST=postgres - export REDIS_EVENTS_STAGING_ENDPOINT=redis:6379 echo "Using docker-internal infra." else export CLICKHOUSE_ADDRESS=localhost:9000 @@ -42,7 +41,6 @@ else export OTLP_DOGFOOD_ENDPOINT=http://localhost:8082/otel export OTLP_ENDPOINT=http://localhost:8082/otel export PSQL_HOST=localhost - export REDIS_EVENTS_STAGING_ENDPOINT=localhost:6379 fi # setup path to include go installed binaries diff --git a/src/dotnet/src/HoldFast.Api/Program.cs b/src/dotnet/src/HoldFast.Api/Program.cs index 4c80feac..e1fffcf1 100644 --- a/src/dotnet/src/HoldFast.Api/Program.cs +++ b/src/dotnet/src/HoldFast.Api/Program.cs @@ -12,7 +12,6 @@ using HoldFast.Shared.Kafka; using HoldFast.Shared.Runtime; using HoldFast.Shared.SessionProcessing; -using HoldFast.Shared.Redis; using HoldFast.Storage; using HoldFast.Worker; using Microsoft.EntityFrameworkCore; @@ -152,11 +151,6 @@ req.RequestUri is null || builder.Configuration.GetSection("Kafka:TopicBootstrap")); builder.Services.AddHostedService(); -// ── Redis ───────────────────────────────────────────────────────────── -builder.Services.Configure( - builder.Configuration.GetSection("Redis")); -builder.Services.AddSingleton(); - // ── ClickHouse ──────────────────────────────────────────────────────── builder.Services.Configure( builder.Configuration.GetSection("ClickHouse")); diff --git a/src/dotnet/src/HoldFast.Shared/HoldFast.Shared.csproj b/src/dotnet/src/HoldFast.Shared/HoldFast.Shared.csproj index a71c233f..4e6509e0 100644 --- a/src/dotnet/src/HoldFast.Shared/HoldFast.Shared.csproj +++ b/src/dotnet/src/HoldFast.Shared/HoldFast.Shared.csproj @@ -11,7 +11,6 @@ - diff --git a/src/dotnet/src/HoldFast.Shared/Redis/RedisService.cs b/src/dotnet/src/HoldFast.Shared/Redis/RedisService.cs deleted file mode 100644 index c784aa54..00000000 --- a/src/dotnet/src/HoldFast.Shared/Redis/RedisService.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Text.Json; -using Microsoft.Extensions.Options; -using StackExchange.Redis; -using Expiration = StackExchange.Redis.Expiration; - -namespace HoldFast.Shared.Redis; - -/// -/// Configuration for Redis connections. Uses StackExchange.Redis connection string format. -/// -public class RedisOptions -{ - public string Configuration { get; set; } = "localhost:6379"; -} - -/// -/// Redis service for caching and distributed state. -/// Replaces go-redis usage in the Go backend. -/// -public class RedisService : IDisposable -{ - private readonly ConnectionMultiplexer _connection; - private readonly IDatabase _db; - - public RedisService(IOptions options) - { - _connection = ConnectionMultiplexer.Connect(options.Value.Configuration); - _db = _connection.GetDatabase(); - } - - public async Task GetAsync(string key) where T : class - { - var value = await _db.StringGetAsync(key); - if (value.IsNullOrEmpty) return null; - return JsonSerializer.Deserialize((string)value!); - } - - public async Task SetAsync(string key, T value, TimeSpan? expiry = null) where T : class - { - var json = JsonSerializer.Serialize(value); - if (expiry.HasValue) - await _db.StringSetAsync(key, json, new Expiration(expiry.Value)); - else - await _db.StringSetAsync(key, json); - } - - public async Task DeleteAsync(string key) - { - return await _db.KeyDeleteAsync(key); - } - - public async Task IncrementAsync(string key) - { - return await _db.StringIncrementAsync(key); - } - - public async Task SetAddAsync(string key, string value) - { - return await _db.SetAddAsync(key, value); - } - - public async Task SetContainsAsync(string key, string value) - { - return await _db.SetContainsAsync(key, value); - } - - public void Dispose() - { - _connection.Dispose(); - } -} diff --git a/src/dotnet/tests/HoldFast.Shared.Tests/Redis/RedisOptionsTests.cs b/src/dotnet/tests/HoldFast.Shared.Tests/Redis/RedisOptionsTests.cs deleted file mode 100644 index 2c127d0f..00000000 --- a/src/dotnet/tests/HoldFast.Shared.Tests/Redis/RedisOptionsTests.cs +++ /dev/null @@ -1,64 +0,0 @@ -using HoldFast.Shared.Redis; -using Xunit; - -namespace HoldFast.Shared.Tests.Redis; - -/// -/// Tests for RedisOptions configuration defaults. -/// RedisService itself requires a running Redis instance, -/// so we test the configuration layer only. -/// -public class RedisOptionsTests -{ - [Fact] - public void RedisOptions_DefaultConfiguration() - { - var options = new RedisOptions(); - Assert.Equal("localhost:6379", options.Configuration); - } - - [Fact] - public void RedisOptions_SetConfiguration() - { - var options = new RedisOptions { Configuration = "redis.internal:6380" }; - Assert.Equal("redis.internal:6380", options.Configuration); - } - - [Fact] - public void RedisOptions_EmptyConfiguration() - { - var options = new RedisOptions { Configuration = "" }; - Assert.Equal("", options.Configuration); - } - - [Fact] - public void RedisOptions_ClusterConfiguration() - { - var options = new RedisOptions - { - Configuration = "redis1:6379,redis2:6379,redis3:6379" - }; - Assert.Contains("redis1", options.Configuration); - Assert.Contains("redis3", options.Configuration); - } - - [Fact] - public void RedisOptions_WithPassword() - { - var options = new RedisOptions - { - Configuration = "redis.internal:6379,password=secret" - }; - Assert.Contains("password=", options.Configuration); - } - - [Fact] - public void RedisOptions_SentinelConfiguration() - { - var options = new RedisOptions - { - Configuration = "sentinel1:26379,sentinel2:26379,serviceName=mymaster" - }; - Assert.Contains("serviceName=", options.Configuration); - } -}