whitfin / cachex

A powerful caching library for Elixir with support for transactions, fallbacks and expirations
https://hexdocs.pm/cachex/
MIT License
1.54k stars 97 forks source link

Advise for testing w/ LocalCluster #221

Closed toranb closed 5 years ago

toranb commented 5 years ago

Today I was migrating a tiny example Phoenix app over from ets and everything worked as expected thanks to the great docs and human friendly source so thank you for this great project!

I did bump into one issue with my test helper for more e2e cluster test scenarios because I'm running LocalCluster before ExUnit right now.

:ok = LocalCluster.start()
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Example.Repo, :manual)

The error message I got was related to multi node as shown below.

** (Cachex.ExecutionError) Attempted to use a local function across nodes
    (cachex) lib/cachex.ex:1405: Cachex.unwrap_unsafe/1

I did some hunting around the test code for Cachex and found this handy Helper method.

  def create_cache_cluster(amount, args \\ [])
  when is_integer(amount) do
    # no-op when done multiple times
    LocalCluster.start()

    name = create_name()
    nodes = [ node() | LocalCluster.start_nodes(name, amount - 1) ]

    # basic match to ensure that the result is as expected
    { [ { :ok, _pid1 }, { :ok, _pid2 } ], [] } = :rpc.multicall(
      nodes,
      Cachex,
      :start,
      [ name, [ nodes: nodes ] ++ args ]
    )

    # stop all children on exit, even though it's automatic
    TestHelper.on_exit("stop #{name} children", fn ->
      nodes
      |> List.delete(node())
      |> LocalCluster.stop_nodes
    end)

    { name, nodes }
  end

The question I have is this -would it be possible to omit the rpc call like I see above and just start each Cachex locally? I don't plan to use this as a distributed cache just yet and if possible I'd like to avoid wiring up anything extra for the bulk of my tests that don't use a cluster as part of the test harness.

Alternative Solution - if you have a pro-tip for running LocalCluster.start only for specific tests I could run w/ that for now. I originally got this working as-is and never had the need to go back and tune my ConnCase and DataCase behaviors to "not start LocalCluster"

The full commit to see this failing test in action can be found using the branch below. I appreciate any help you can provide to get me moving in the right direction :)

https://github.com/toranb/elixir-budget/commit/ebddb9a6b48eaaba072b3a1070bd6ed1471c833d

toranb commented 5 years ago

Well funny enough all I needed to do was move the LocalCluster.start line to the only test that needed it. For some odd reason I thought reading the docs for LocalCluster that you needed to have this line run before ExUnit.start ... seems not?

https://github.com/toranb/elixir-budget/commit/b657a1824dbc9db2f6ea4bf5ce62460173e4b423