From 537057ee9af37e5915c1acc1cdb12d4e56e4a0f7 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Wed, 22 Oct 2025 16:30:04 -0500 Subject: [PATCH] more redis cleanup --- lib/aprsme/redis_rate_limiter.ex | 165 --------------------------- lib/aprsme_web/plugs/health_check.ex | 18 +-- 2 files changed, 1 insertion(+), 182 deletions(-) delete mode 100644 lib/aprsme/redis_rate_limiter.ex diff --git a/lib/aprsme/redis_rate_limiter.ex b/lib/aprsme/redis_rate_limiter.ex deleted file mode 100644 index cd836b0..0000000 --- a/lib/aprsme/redis_rate_limiter.ex +++ /dev/null @@ -1,165 +0,0 @@ -defmodule Aprsme.RedisRateLimiter do - @moduledoc """ - Redis-backed distributed rate limiter using sliding window algorithm. - """ - - require Logger - - # 5 seconds timeout for Redis operations - @redis_timeout 5000 - - def child_spec(_opts) do - children = [ - {Redix, name: __MODULE__, host: redis_host(), port: redis_port(), password: redis_password()} - ] - - %{ - id: __MODULE__, - type: :supervisor, - start: {Supervisor, :start_link, [children, [strategy: :one_for_one, name: :"#{__MODULE__}_supervisor"]]} - } - end - - @doc """ - Check rate limit using sliding window algorithm. - - ## Parameters - - bucket: The rate limit bucket (e.g., "user:123" or "ip:192.168.1.1") - - limit: Maximum number of requests allowed - - window_ms: Time window in milliseconds - - ## Returns - - {:allow, count} if under limit - - {:deny, limit} if over limit - """ - def check_rate(bucket, limit, window_ms) do - now = System.system_time(:millisecond) - window_start = now - window_ms - key = make_key(bucket) - - # Lua script for atomic sliding window rate limiting - lua_script = """ - local key = KEYS[1] - local now = tonumber(ARGV[1]) - local window_start = tonumber(ARGV[2]) - local limit = tonumber(ARGV[3]) - - -- Remove old entries - redis.call('ZREMRANGEBYSCORE', key, 0, window_start) - - -- Count current entries - local current = redis.call('ZCARD', key) - - if current < limit then - -- Add new entry - redis.call('ZADD', key, now, now) - -- Set expiry - redis.call('EXPIRE', key, math.ceil(ARGV[4] / 1000)) - return {1, current + 1} - else - return {0, limit} - end - """ - - case Redix.command(__MODULE__, ["EVAL", lua_script, 1, key, now, window_start, limit, window_ms], - timeout: @redis_timeout - ) do - {:ok, [1, count]} -> - {:allow, count} - - {:ok, [0, limit]} -> - {:deny, limit} - - {:error, reason} -> - Logger.error("Redis rate limit error for #{bucket}: #{inspect(reason)}") - # Fail open - allow request if Redis is down - {:allow, 1} - end - end - - @doc """ - Reset rate limit for a bucket - """ - def reset(bucket) do - key = make_key(bucket) - - case Redix.command(__MODULE__, ["DEL", key], timeout: @redis_timeout) do - {:ok, _} -> - :ok - - {:error, reason} -> - Logger.error("Redis rate limit reset error for #{bucket}: #{inspect(reason)}") - {:error, reason} - end - end - - @doc """ - Get current count for a bucket - """ - def count(bucket, window_ms) do - now = System.system_time(:millisecond) - window_start = now - window_ms - key = make_key(bucket) - - # Clean up old entries and count - case Redix.pipeline( - __MODULE__, - [ - ["ZREMRANGEBYSCORE", key, 0, window_start], - ["ZCARD", key] - ], - timeout: @redis_timeout - ) do - {:ok, [_, count]} -> - {:ok, count} - - {:error, reason} -> - Logger.error("Redis rate limit count error for #{bucket}: #{inspect(reason)}") - {:error, reason} - end - end - - @doc """ - Get remaining requests for a bucket - """ - def remaining(bucket, limit, window_ms) do - case count(bucket, window_ms) do - {:ok, current} -> {:ok, max(0, limit - current)} - error -> error - end - end - - # Private functions - - defp make_key(bucket) do - "aprsme:rate_limit:#{bucket}" - end - - defp redis_host do - redis_url = System.get_env("REDIS_URL", "redis://localhost:6379") - uri = URI.parse(redis_url) - uri.host || "localhost" - end - - defp redis_port do - redis_url = System.get_env("REDIS_URL", "redis://localhost:6379") - uri = URI.parse(redis_url) - uri.port || 6379 - end - - defp redis_password do - redis_url = System.get_env("REDIS_URL", "redis://localhost:6379") - uri = URI.parse(redis_url) - - case uri.userinfo do - nil -> - nil - - userinfo -> - case String.split(userinfo, ":") do - [_, password] -> password - _ -> nil - end - end - end -end diff --git a/lib/aprsme_web/plugs/health_check.ex b/lib/aprsme_web/plugs/health_check.ex index bf3e8c6..8d588f8 100644 --- a/lib/aprsme_web/plugs/health_check.ex +++ b/lib/aprsme_web/plugs/health_check.ex @@ -69,8 +69,7 @@ defmodule AprsmeWeb.Plugs.HealthCheck do defp full_health_checks do # Comprehensive checks for readiness - with :ok <- check_database_connection(), - :ok <- check_redis_connection() do + with :ok <- check_database_connection() do check_pubsub() end end @@ -84,21 +83,6 @@ defmodule AprsmeWeb.Plugs.HealthCheck do _ -> {:error, "Database check failed"} end - defp check_redis_connection do - if System.get_env("REDIS_URL") do - try do - case Redix.command(:query_cache_redis, ["PING"]) do - {:ok, "PONG"} -> :ok - _ -> {:error, "Redis connection failed"} - end - rescue - _ -> {:error, "Redis check failed"} - end - else - :ok - end - end - defp check_pubsub do Phoenix.PubSub.broadcast(Aprsme.PubSub, "health_check", :ping) :ok