Remove Redis/Cachex dependency, use pure ETS for caching
- Replace Cachex with native ETS (Erlang Term Storage) in Cache module - Remove Redis-based caching logic from application.ex - Always initialize ETS tables for device_cache, query_cache, symbol_cache - Update StatusLive to use Aprsme.Cache instead of Cachex directly - Fix crash on startup when REDIS_URL was set but Redis not used This fixes the no_cache error that was causing pods to crash.
This commit is contained in:
parent
18d95b9a1f
commit
ae14b120fa
3 changed files with 54 additions and 34 deletions
|
|
@ -235,24 +235,18 @@ defmodule Aprsme.Application do
|
|||
# end
|
||||
|
||||
defp redis_children do
|
||||
if System.get_env("REDIS_URL") do
|
||||
require Logger
|
||||
require Logger
|
||||
|
||||
Logger.info("Starting Redis-based caching and rate limiting")
|
||||
Logger.info("Starting ETS-based caching and rate limiting")
|
||||
|
||||
[]
|
||||
else
|
||||
require Logger
|
||||
# Create ETS tables for caching
|
||||
:ets.new(:query_cache, [:set, :public, :named_table, read_concurrency: true])
|
||||
:ets.new(:device_cache, [:set, :public, :named_table, read_concurrency: true])
|
||||
:ets.new(:symbol_cache, [:set, :public, :named_table, read_concurrency: true])
|
||||
|
||||
Logger.info("Starting ETS-based caching and rate limiting (no Redis URL)")
|
||||
|
||||
[
|
||||
# Fallback to ETS-based implementations
|
||||
Aprsme.RateLimiter,
|
||||
%{id: :query_cache, start: {Cachex, :start_link, [:query_cache, [limit: 10_000]]}},
|
||||
%{id: :device_cache, start: {Cachex, :start_link, [:device_cache, [limit: 5_000]]}},
|
||||
%{id: :symbol_cache, start: {Cachex, :start_link, [:symbol_cache, [limit: 1_000]]}}
|
||||
]
|
||||
end
|
||||
[
|
||||
# ETS-based rate limiter
|
||||
Aprsme.RateLimiter
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,59 +1,85 @@
|
|||
defmodule Aprsme.Cache do
|
||||
@moduledoc """
|
||||
Cache abstraction layer that works with both Cachex and RedisCache.
|
||||
Provides a unified API regardless of the underlying implementation.
|
||||
Cache abstraction layer using ETS (Erlang Term Storage).
|
||||
Provides a unified API for in-memory caching.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Get a value from cache
|
||||
"""
|
||||
def get(cache_name, key) do
|
||||
Cachex.get(cache_name, key)
|
||||
case :ets.lookup(cache_name, key) do
|
||||
[{^key, value}] -> {:ok, value}
|
||||
[] -> {:ok, nil}
|
||||
end
|
||||
rescue
|
||||
ArgumentError -> {:error, :no_cache}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Put a value in cache with optional TTL
|
||||
Put a value in cache with optional TTL (TTL not implemented for ETS)
|
||||
"""
|
||||
def put(cache_name, key, value, opts \\ []) do
|
||||
Cachex.put(cache_name, key, value, opts)
|
||||
def put(cache_name, key, value, _opts \\ []) do
|
||||
try do
|
||||
:ets.insert(cache_name, {key, value})
|
||||
{:ok, true}
|
||||
rescue
|
||||
ArgumentError -> {:error, :no_cache}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Delete a key from cache
|
||||
"""
|
||||
def del(cache_name, key) do
|
||||
Cachex.del(cache_name, key)
|
||||
try do
|
||||
:ets.delete(cache_name, key)
|
||||
{:ok, true}
|
||||
rescue
|
||||
ArgumentError -> {:error, :no_cache}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Clear all keys from cache
|
||||
"""
|
||||
def clear(cache_name) do
|
||||
Cachex.clear(cache_name)
|
||||
try do
|
||||
:ets.delete_all_objects(cache_name)
|
||||
{:ok, true}
|
||||
rescue
|
||||
ArgumentError -> {:error, :no_cache}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get cache statistics
|
||||
Get cache statistics (simplified for ETS)
|
||||
"""
|
||||
def stats(cache_name) do
|
||||
Cachex.stats(cache_name)
|
||||
try do
|
||||
info = :ets.info(cache_name)
|
||||
{:ok, %{size: Keyword.get(info, :size, 0)}}
|
||||
rescue
|
||||
ArgumentError -> {:error, :no_cache}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Check if key exists
|
||||
"""
|
||||
def exists?(cache_name, key) do
|
||||
case Cachex.exists?(cache_name, key) do
|
||||
{:ok, exists?} -> exists?
|
||||
{:error, _reason} -> false
|
||||
try do
|
||||
:ets.member(cache_name, key)
|
||||
rescue
|
||||
ArgumentError -> false
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get TTL for a key
|
||||
Get TTL for a key (not supported in ETS, always returns nil)
|
||||
"""
|
||||
def ttl(cache_name, key) do
|
||||
Cachex.ttl(cache_name, key)
|
||||
def ttl(_cache_name, _key) do
|
||||
{:ok, nil}
|
||||
end
|
||||
|
||||
# Helper functions - no longer needed as we only use Cachex
|
||||
|
|
|
|||
|
|
@ -395,14 +395,14 @@ defmodule AprsmeWeb.StatusLive.Index do
|
|||
|
||||
defp get_cached_aprs_status do
|
||||
# Try to get cached status for instant load
|
||||
case Cachex.get(:query_cache, "aprs_status") do
|
||||
case Aprsme.Cache.get(:query_cache, "aprs_status") do
|
||||
{:ok, status} when not is_nil(status) ->
|
||||
status
|
||||
|
||||
_ ->
|
||||
# Fallback to direct query if cache miss
|
||||
status = get_aprs_status()
|
||||
Cachex.put(:query_cache, "aprs_status", status, ttl: to_timeout(second: 5))
|
||||
Aprsme.Cache.put(:query_cache, "aprs_status", status)
|
||||
status
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue