-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document test env setup with decorators? #155
Comments
Having the exact same issue... Is there a way to use the Null Adapter with decorators? |
Hey 👋 !! Well, the main limitation is decorations are evaluated in compilation time, so yes, the cache you pass there is the real implementation. I think there may be several ways to address this, but let me mention a workaround I've used myself in these cases. You can add a configuration parameter at the app level to define the adapter to use, for example: adapter = Application.get_env(:my_app, :cache_adapter, Nebulex.Adapters.Local)
defmodule MyApp.Cache do
otp_app: :my_app,
adapter: adapter
end And then you can use the different config files depending on the environment, for example in the config :my_app,
cache_adapter: Nebulex.Adapters.Nil It is a very naive/simple workaround but it has worked for me, maybe not the best, but it helps to address the need of having different adapters depending on the environment. I will think if there is something else we can do about it, but in the meantime let me know if the workaround works for you. Thanks! |
Thanks for a quick reply! Do you think it may be possible to modify the decorator to accept a function returning the cache at runtime? Something among the lines of: defp cache, do: Application.fetch_env!(:my_app, :cache)
@decorate cacheable(cache: &cache/1)
def get_account(id) do
...
end Would you be interested in a PR for this feature? |
Hey @suzdalnitski !! yeah, I think it is possible, in fact, the options
Absolutely !!! |
While I think this is a good direction, it just seems to move the problem a little. So this does allow run-time evaluation in the decorator, but because the alternative implementation is not also evaluated in I have to specifically evaluate the value at compile time, so I can also start the right process. My working implementation looks like this:
defmodule MyApp.Cache do
@cache_implementation Application.compile_env(:my_app, :cache_implementation, MyApp.Cache.Local)
def dynamic_cache do
@cache_implementation
end
defmodule Local do
use Nebulex.Cache, otp_app: :my_app, adapter: Nebulex.Adapters.Local
end
defmodule Nil do
use Nebulex.Cache, otp_app: :my_app, adapter: Nebulex.Adapters.Nil
end
end
...
children = [
MyApp.Cache.dynamic_cache(),
...
...
config :my_app, :cache_implementation, MyApp.Cache.dynamic_cache()
... Now the cache decorator can work with the runtime mfa tuple like |
You still need to start the cache, here's how I'm doing this in tests (based on the defmodule MyApp.CacheCase do
use ExUnit.CaseTemplate
alias Ecto.Adapters.SQL.Sandbox
using do
quote do
import Ecto
import Ecto.Changeset
import Ecto.Query
end
end
setup _ do
# Ecto setup
:ok = Sandbox.checkout(MyApp.Repo)
Sandbox.mode(MyApp.Repo, {:shared, self()})
# Start the cache
{:ok, cache_pid} = MyApp.Cache.LiveCache.start_link()
Application.put_env(:my_app, :cache, MyApp.Cache.LiveCache)
# Stop the cache on exit
on_exit(fn ->
if Process.alive?(cache_pid), do: Process.exit(cache_pid, :normal)
Application.put_env(:my_app, :cache, MyApp.Cache.TestCache)
end)
:ok
end
end The caches are defined as: defmodule MyApp.Cache.LiveCache do
use Nebulex.Cache,
otp_app: :my_app,
adapter: Nebulex.Adapters.Local
end
defmodule MyApp.Cache.TestCache do
use Nebulex.Cache,
otp_app: :my_app,
adapter: Nebulex.Adapters.Nil
end Then make sure that you're running this as async within your tests: use MyApp.CacheCase, async: false |
@cabol |
@suzdalnitski sorry for the lateness, I've been pretty busy, I checked it already and I added a comment
So, the PR is merged, but will push some fixes and/or improvements soon. Also, I created another ticket documenting the feature a bit better #157 |
@cabol That's great, thank you! |
Closing this issue since some workarounds have been shared and the ability to resolve the cache in decorators at runtime. However, for Nevbulex v3.0.0 I'm planning to address this better, not only with the decorators but in general, so suggestions or ideas are welcome, feel free to open an issue with the proposal. |
I'm able to easily switch adapters before the supervision tree starts, but I'm somewhat confused on the best approach to the decorator pattern and how it might work with different implementations.
In any given module I have
@decorator cacheable(cache: MyApp.Cache.Local)
. The problem is thatMyApp.Cache.Local
is the real implementation, not an alias or a mock. I know I could do something messy checking theMix.env
and setting an appropriate alias in each module. But Is there a good way to define the mock class at a higher level like in application.ex or config.ex?The text was updated successfully, but these errors were encountered: