aprs.me/lib/aprsme/rate_limiter_wrapper.ex
Graham McIntire 226a53bf61
Add Redis-based distributed caching and rate limiting
This commit introduces a dual-mode caching and rate limiting system that can use
either Redis (for distributed deployments) or ETS/Cachex (for single-node setups).

Key changes:
- Add Cache abstraction layer that automatically switches between Redis and Cachex
- Implement RedisCache module with full distributed cache functionality
- Implement RedisRateLimiter with sliding window algorithm for accurate rate limiting
- Add RateLimiterWrapper to provide unified API for both implementations
- Update application startup to conditionally use Redis when REDIS_URL is set
- Migrate all cache operations to use the new Cache abstraction
- Support graceful fallback to ETS-based solutions when Redis is unavailable

The system automatically detects Redis availability via REDIS_URL environment
variable and switches between implementations without code changes. This enables
proper distributed caching and rate limiting in Kubernetes deployments while
maintaining backward compatibility for development environments.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-26 15:29:38 -05:00

46 lines
1,023 B
Elixir

defmodule Aprsme.RateLimiterWrapper do
@moduledoc """
Wrapper that provides the same API for both Hammer and RedisRateLimiter
"""
@doc """
Check rate limit - compatible with Hammer.hit/3 API
"""
def hit(bucket, scale_ms, limit) do
if using_redis?() do
Aprsme.RedisRateLimiter.check_rate(bucket, limit, scale_ms)
else
Aprsme.RateLimiter.hit(bucket, scale_ms, limit)
end
end
@doc """
Reset rate limit for a bucket
"""
def reset(bucket) do
if using_redis?() do
Aprsme.RedisRateLimiter.reset(bucket)
else
# Hammer doesn't provide a reset function
# Best we can do is return ok
:ok
end
end
@doc """
Get current count for a bucket
"""
def count(bucket, scale_ms) do
if using_redis?() do
Aprsme.RedisRateLimiter.count(bucket, scale_ms)
else
# Hammer doesn't provide a count function
# Return 0 as default
{:ok, 0}
end
end
defp using_redis? do
System.get_env("REDIS_URL") != nil
end
end