cleanup and remove redis
This commit is contained in:
parent
6acc007360
commit
cc4578653f
7 changed files with 21 additions and 324 deletions
|
|
@ -240,14 +240,7 @@ defmodule Aprsme.Application do
|
|||
|
||||
Logger.info("Starting Redis-based caching and rate limiting")
|
||||
|
||||
[
|
||||
# Redis-based rate limiter
|
||||
Aprsme.RedisRateLimiter,
|
||||
# Redis-based caches
|
||||
{Aprsme.RedisCache, name: :query_cache},
|
||||
{Aprsme.RedisCache, name: :device_cache},
|
||||
{Aprsme.RedisCache, name: :symbol_cache}
|
||||
]
|
||||
[]
|
||||
else
|
||||
require Logger
|
||||
|
||||
|
|
|
|||
|
|
@ -8,70 +8,44 @@ defmodule Aprsme.Cache do
|
|||
Get a value from cache
|
||||
"""
|
||||
def get(cache_name, key) do
|
||||
if using_redis?() do
|
||||
Aprsme.RedisCache.get(cache_name, key)
|
||||
else
|
||||
Cachex.get(cache_name, key)
|
||||
end
|
||||
Cachex.get(cache_name, key)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Put a value in cache with optional TTL
|
||||
"""
|
||||
def put(cache_name, key, value, opts \\ []) do
|
||||
if using_redis?() do
|
||||
# Convert TTL from milliseconds to seconds for Redis, preserving sub-second values
|
||||
opts = convert_ttl_to_seconds(opts)
|
||||
Aprsme.RedisCache.put(cache_name, key, value, opts)
|
||||
else
|
||||
Cachex.put(cache_name, key, value, opts)
|
||||
end
|
||||
Cachex.put(cache_name, key, value, opts)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Delete a key from cache
|
||||
"""
|
||||
def del(cache_name, key) do
|
||||
if using_redis?() do
|
||||
Aprsme.RedisCache.del(cache_name, key)
|
||||
else
|
||||
Cachex.del(cache_name, key)
|
||||
end
|
||||
Cachex.del(cache_name, key)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Clear all keys from cache
|
||||
"""
|
||||
def clear(cache_name) do
|
||||
if using_redis?() do
|
||||
Aprsme.RedisCache.clear(cache_name)
|
||||
else
|
||||
Cachex.clear(cache_name)
|
||||
end
|
||||
Cachex.clear(cache_name)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get cache statistics
|
||||
"""
|
||||
def stats(cache_name) do
|
||||
if using_redis?() do
|
||||
Aprsme.RedisCache.stats(cache_name)
|
||||
else
|
||||
Cachex.stats(cache_name)
|
||||
end
|
||||
Cachex.stats(cache_name)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Check if key exists
|
||||
"""
|
||||
def exists?(cache_name, key) do
|
||||
if using_redis?() do
|
||||
Aprsme.RedisCache.exists?(cache_name, key)
|
||||
else
|
||||
case Cachex.exists?(cache_name, key) do
|
||||
{:ok, exists?} -> exists?
|
||||
{:error, _reason} -> false
|
||||
end
|
||||
case Cachex.exists?(cache_name, key) do
|
||||
{:ok, exists?} -> exists?
|
||||
{:error, _reason} -> false
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -79,35 +53,10 @@ defmodule Aprsme.Cache do
|
|||
Get TTL for a key
|
||||
"""
|
||||
def ttl(cache_name, key) do
|
||||
if using_redis?() do
|
||||
Aprsme.RedisCache.ttl(cache_name, key)
|
||||
else
|
||||
Cachex.ttl(cache_name, key)
|
||||
end
|
||||
Cachex.ttl(cache_name, key)
|
||||
end
|
||||
|
||||
# Helper functions
|
||||
|
||||
defp using_redis? do
|
||||
System.get_env("REDIS_URL") != nil
|
||||
end
|
||||
|
||||
defp convert_ttl_to_seconds(opts) do
|
||||
case Keyword.get(opts, :ttl) do
|
||||
nil ->
|
||||
opts
|
||||
|
||||
ttl_ms when is_integer(ttl_ms) and ttl_ms > 0 ->
|
||||
ttl_seconds = ttl_ms |> Integer.ceil_div(1000) |> max(1)
|
||||
Keyword.put(opts, :ttl, ttl_seconds)
|
||||
|
||||
ttl_ms when is_integer(ttl_ms) ->
|
||||
Keyword.put(opts, :ttl, ttl_ms)
|
||||
|
||||
_ ->
|
||||
opts
|
||||
end
|
||||
end
|
||||
# Helper functions - no longer needed as we only use Cachex
|
||||
|
||||
@doc """
|
||||
Convert timeout keyword list to milliseconds
|
||||
|
|
|
|||
|
|
@ -1,251 +0,0 @@
|
|||
defmodule Aprsme.RedisCache do
|
||||
@moduledoc """
|
||||
Redis-backed distributed cache implementation.
|
||||
Provides a similar API to Cachex but uses Redis for distributed caching.
|
||||
"""
|
||||
|
||||
require Logger
|
||||
|
||||
# 5 minutes in seconds
|
||||
@default_ttl 300
|
||||
# 5 seconds timeout for Redis operations
|
||||
@redis_timeout 5000
|
||||
|
||||
def child_spec(opts) do
|
||||
name = Keyword.fetch!(opts, :name)
|
||||
|
||||
children = [
|
||||
{Redix, name: redis_name(name), host: redis_host(), port: redis_port(), password: redis_password()}
|
||||
]
|
||||
|
||||
%{
|
||||
id: {__MODULE__, name},
|
||||
type: :supervisor,
|
||||
start: {Supervisor, :start_link, [children, [strategy: :one_for_one, name: :"#{name}_redis_supervisor"]]}
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get a value from the cache
|
||||
"""
|
||||
def get(cache_name, key) do
|
||||
redis_key = make_redis_key(cache_name, key)
|
||||
|
||||
case Redix.command(redis_name(cache_name), ["GET", redis_key], timeout: @redis_timeout) do
|
||||
{:ok, nil} ->
|
||||
{:ok, nil}
|
||||
|
||||
{:ok, value} ->
|
||||
{:ok, deserialize(value)}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Redis GET error for #{redis_key}: #{inspect(reason)}")
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Put a value in the cache with optional TTL
|
||||
"""
|
||||
def put(cache_name, key, value, opts \\ []) do
|
||||
redis_key = make_redis_key(cache_name, key)
|
||||
ttl = Keyword.get(opts, :ttl, @default_ttl)
|
||||
serialized = serialize(value)
|
||||
|
||||
case Redix.command(redis_name(cache_name), ["SETEX", redis_key, ttl, serialized], timeout: @redis_timeout) do
|
||||
{:ok, "OK"} ->
|
||||
{:ok, true}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Redis SETEX error for #{redis_key}: #{inspect(reason)}")
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Delete a value from the cache
|
||||
"""
|
||||
def del(cache_name, key) do
|
||||
redis_key = make_redis_key(cache_name, key)
|
||||
|
||||
case Redix.command(redis_name(cache_name), ["DEL", redis_key], timeout: @redis_timeout) do
|
||||
{:ok, _} ->
|
||||
{:ok, true}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Redis DEL error for #{redis_key}: #{inspect(reason)}")
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Delete multiple keys matching a pattern
|
||||
"""
|
||||
def del_pattern(cache_name, pattern) do
|
||||
redis_pattern = make_redis_key(cache_name, pattern)
|
||||
|
||||
# Use SCAN to find keys matching pattern
|
||||
case scan_keys(cache_name, redis_pattern) do
|
||||
{:ok, keys} when keys != [] ->
|
||||
case Redix.command(redis_name(cache_name), ["DEL" | keys], timeout: @redis_timeout) do
|
||||
{:ok, count} ->
|
||||
{:ok, count}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Redis DEL error for pattern #{redis_pattern}: #{inspect(reason)}")
|
||||
{:error, reason}
|
||||
end
|
||||
|
||||
{:ok, []} ->
|
||||
{:ok, 0}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Clear all keys for a cache
|
||||
"""
|
||||
def clear(cache_name) do
|
||||
pattern = make_redis_key(cache_name, "*")
|
||||
|
||||
case scan_keys(cache_name, pattern) do
|
||||
{:ok, keys} when keys != [] ->
|
||||
case Redix.pipeline(redis_name(cache_name), Enum.map(keys, &["DEL", &1]), timeout: @redis_timeout) do
|
||||
{:ok, _results} ->
|
||||
{:ok, true}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Redis CLEAR error for #{cache_name}: #{inspect(reason)}")
|
||||
{:error, reason}
|
||||
end
|
||||
|
||||
{:ok, []} ->
|
||||
{:ok, true}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get cache statistics
|
||||
"""
|
||||
def stats(cache_name) do
|
||||
pattern = make_redis_key(cache_name, "*")
|
||||
|
||||
case scan_keys(cache_name, pattern) do
|
||||
{:ok, keys} ->
|
||||
{:ok,
|
||||
%{
|
||||
size: length(keys),
|
||||
keys: keys
|
||||
}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Check if a key exists
|
||||
"""
|
||||
def exists?(cache_name, key) do
|
||||
redis_key = make_redis_key(cache_name, key)
|
||||
|
||||
case Redix.command(redis_name(cache_name), ["EXISTS", redis_key], timeout: @redis_timeout) do
|
||||
{:ok, 1} -> true
|
||||
{:ok, 0} -> false
|
||||
{:error, _} -> false
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get remaining TTL for a key
|
||||
"""
|
||||
def ttl(cache_name, key) do
|
||||
redis_key = make_redis_key(cache_name, key)
|
||||
|
||||
case Redix.command(redis_name(cache_name), ["TTL", redis_key], timeout: @redis_timeout) do
|
||||
# Key doesn't exist
|
||||
{:ok, -2} -> {:ok, nil}
|
||||
# Key exists but has no TTL
|
||||
{:ok, -1} -> {:ok, :infinity}
|
||||
{:ok, seconds} -> {:ok, seconds}
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
# Private functions
|
||||
|
||||
defp redis_name(cache_name), do: :"#{cache_name}_redis"
|
||||
|
||||
defp make_redis_key(cache_name, key) when is_binary(key) do
|
||||
"aprsme:#{cache_name}:#{key}"
|
||||
end
|
||||
|
||||
defp make_redis_key(cache_name, key) do
|
||||
"aprsme:#{cache_name}:#{:erlang.phash2(key)}"
|
||||
end
|
||||
|
||||
defp serialize(value) do
|
||||
:erlang.term_to_binary(value)
|
||||
end
|
||||
|
||||
defp deserialize(binary) when is_binary(binary) do
|
||||
:erlang.binary_to_term(binary)
|
||||
rescue
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
defp scan_keys(cache_name, pattern) do
|
||||
scan_keys(cache_name, pattern, "0", [])
|
||||
end
|
||||
|
||||
defp scan_keys(cache_name, pattern, cursor, acc) do
|
||||
case Redix.command(redis_name(cache_name), ["SCAN", cursor, "MATCH", pattern, "COUNT", "100"],
|
||||
timeout: @redis_timeout
|
||||
) do
|
||||
{:ok, [new_cursor, keys]} ->
|
||||
new_acc = acc ++ keys
|
||||
|
||||
if new_cursor == "0" do
|
||||
{:ok, new_acc}
|
||||
else
|
||||
scan_keys(cache_name, pattern, new_cursor, new_acc)
|
||||
end
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
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
|
||||
|
|
@ -134,11 +134,14 @@ defmodule AprsmeWeb.MapLive.DataBuilder do
|
|||
@spec valid_coordinates?(any(), any()) :: boolean()
|
||||
defp valid_coordinates?(lat, lon) when is_number(lat) and is_number(lon) do
|
||||
lat >= -90 and lat <= 90 and lon >= -180 and lon <= 180 and
|
||||
:math.is_finite(lat) and :math.is_finite(lon)
|
||||
is_finite(lat) and is_finite(lon)
|
||||
end
|
||||
|
||||
defp valid_coordinates?(_, _), do: false
|
||||
|
||||
defp is_finite(n) when is_float(n), do: n != :infinity and n != :neg_infinity and n == n
|
||||
defp is_finite(n) when is_integer(n), do: true
|
||||
|
||||
@doc """
|
||||
Build packet data list for historical display.
|
||||
Moved from historical_loader.ex.
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ defmodule AprsmeWeb.MapLive.HistoricalLoader do
|
|||
|
||||
is_number(lat) and is_number(lon) and
|
||||
lat >= -90 and lat <= 90 and lon >= -180 and lon <= 180 and
|
||||
:math.is_finite(lat) and :math.is_finite(lon)
|
||||
is_finite(lat) and is_finite(lon)
|
||||
end)
|
||||
|
||||
if length(valid_packets) < length(historical_packets) do
|
||||
|
|
@ -430,4 +430,7 @@ defmodule AprsmeWeb.MapLive.HistoricalLoader do
|
|||
|
||||
socket
|
||||
end
|
||||
|
||||
defp is_finite(n) when is_float(n), do: n != :infinity and n != :neg_infinity and n == n
|
||||
defp is_finite(n) when is_integer(n), do: true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ defmodule AprsmeWeb.Plugs.ApiCSRF do
|
|||
reject_request(conn)
|
||||
|
||||
session_token ->
|
||||
if Plug.CSRFProtection.verify_csrf_token(token, session_token) do
|
||||
if Plug.CSRFProtection.valid_state_and_csrf_token?(session_token, token) do
|
||||
conn
|
||||
else
|
||||
reject_request(conn)
|
||||
|
|
|
|||
2
vendor/aprs
vendored
2
vendor/aprs
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 0d0d21d9e9a342abdb486a4bc8650542df9e38ed
|
||||
Subproject commit 84a410daf78f720af03701c6ab5b24fdf7cfd0b3
|
||||
Loading…
Add table
Reference in a new issue