-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Abstract out provisioning across all component types
- Loading branch information
Showing
11 changed files
with
181 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
defmodule Cachex.Provision do | ||
@moduledoc """ | ||
Module controlling provisioning behaviour definitions. | ||
This module defines the provisioning implementation for Cachex, allowing | ||
components such as hooks and warmers to tap into state changes in the cache | ||
table. By implementing `handle_provision/2` these components can be provided | ||
with new versions of state as they're created. | ||
""" | ||
|
||
############# | ||
# Behaviour # | ||
############# | ||
|
||
@doc """ | ||
Returns an enumerable of provisions this implementation requires. | ||
The current provisions available are: | ||
* `cache` - a cache instance used to make cache calls with lower overhead. | ||
This should always return an enumerable of atoms; in the case of no required | ||
provisions an empty enumerable should be returned. | ||
""" | ||
@callback provisions :: [atom] | ||
|
||
@doc """ | ||
Handles a provisioning call. | ||
The provided argument will be a Tuple dictating the type of value being | ||
provisioned along with the value itself. This can be used to listen on | ||
states required for hook executions (such as cache records). | ||
""" | ||
@callback handle_provision({atom, any}, any) :: {:ok, any} | ||
|
||
################## | ||
# Implementation # | ||
################## | ||
|
||
@doc false | ||
defmacro __using__(_) do | ||
quote location: :keep do | ||
# use the provision behaviour | ||
@behaviour Cachex.Provision | ||
|
||
################# | ||
# Configuration # | ||
################# | ||
|
||
@doc false | ||
def provisions, | ||
do: [] | ||
|
||
# config overrides | ||
defoverridable provisions: 0 | ||
|
||
######################### | ||
# Notification Handlers # | ||
######################### | ||
|
||
@doc false | ||
def handle_provision(provision, state), | ||
do: {:ok, state} | ||
|
||
# listener override | ||
defoverridable handle_provision: 2 | ||
|
||
########################## | ||
# Private Implementation # | ||
########################## | ||
|
||
@doc false | ||
def handle_info({:cachex_provision, provision}, state) do | ||
{:ok, new_state} = handle_provision(provision, state) | ||
{:noreply, new_state} | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
defmodule Cachex.Services.Steward do | ||
@moduledoc """ | ||
Service module overseeing cache provisions. | ||
This module controls state provision to Cachex components, such as hooks | ||
and warmers. In previous versions of Cachex provisions were handled under | ||
the `Cachex.Hook` behaviour, but the introduction of warmers meant that it | ||
should be handled in a separate location. | ||
This service module will handle the provision of state to relevant components | ||
attached to a cache, without the caller having to think about it. | ||
""" | ||
import Cachex.Spec | ||
|
||
# recognised | ||
@provisions [ | ||
:cache | ||
] | ||
|
||
############## | ||
# Public API # | ||
############## | ||
|
||
@doc """ | ||
Provides an state pair to relevant components. | ||
This will send updated state to all interest components, but does not | ||
wait for a response before returning. As provisions are handled in a | ||
base implementation, we can be sure of safe implementation here. | ||
""" | ||
@spec provide(Cachex.Spec.cache(), {atom, any}) :: :ok | ||
def provide(cache() = cache, {key, _} = provision) when key in @provisions do | ||
cache(hooks: hooks(pre: pre_hooks, post: post_hooks)) = cache | ||
cache(warmers: warmers) = cache | ||
|
||
hook_pairs = | ||
pre_hooks | ||
|> Enum.concat(post_hooks) | ||
|> Enum.map(fn hook(module: mod, name: name) -> {name, mod} end) | ||
|
||
warmer_pairs = | ||
warmers | ||
|> Enum.map(fn warmer(module: mod) -> {mod, mod} end) | ||
|
||
warmer_pairs | ||
|> Enum.concat(hook_pairs) | ||
|> Enum.filter(fn {_, mod} -> key in mod.provisions() end) | ||
|> Enum.each(fn {name, _} -> send(name, {:cachex_provision, provision}) end) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
defmodule Cachex.Services.StewardTest do | ||
use CachexCase | ||
|
||
test "provisioning cache state" do | ||
# bind our hook | ||
ForwardHook.bind( | ||
steward_forward_hook_provisions: [ | ||
provisions: [:cache] | ||
] | ||
) | ||
|
||
# create our hook with the provisions forwarded through to it | ||
hook = ForwardHook.create(:steward_forward_hook_provisions) | ||
|
||
# start a new cache using our forwarded hook | ||
cache = Helper.create_cache(hooks: [hook]) | ||
cache = Services.Overseer.retrieve(cache) | ||
|
||
# the provisioned value should match | ||
assert_receive({:cache, ^cache}) | ||
end | ||
end |
Oops, something went wrong.