Skip to content

Commit fab6655

Browse files
committed
add batteries
1 parent 40d717f commit fab6655

12 files changed

Lines changed: 450 additions & 176 deletions

File tree

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,41 @@ def deps do
1515
end
1616
```
1717

18+
## Configuration
19+
20+
The following configuration is available:
21+
22+
```elixir
23+
if Mix.env() === :test do
24+
config :cloud_cache, CloudCache.Adapters.S3,
25+
auto_start: true,
26+
sandbox_enabled: true
27+
else
28+
config :cloud_cache, CloudCache.Adapters.S3,
29+
auto_start: true,
30+
sandbox_enabled: false,
31+
retries: [
32+
max_attempts: 10,
33+
base_backoff_in_ms: 10,
34+
max_backoff_in_ms: 10_000
35+
],
36+
access_key_id: [
37+
{:awscli, System.get_env("AWS_PROFILE", "default"), 30},
38+
{:awscli, System.get_env("AWS_PROFILE", "cloud_cache"), 30},
39+
{:system, "CLOUD_CACHE_AWS_ACCESS_KEY_ID"},
40+
{:system, "AWS_ACCESS_KEY_ID"},
41+
:instance_role
42+
],
43+
secret_access_key: [
44+
{:awscli, System.get_env("AWS_PROFILE", "default"), 30},
45+
{:awscli, System.get_env("AWS_PROFILE", "cloud_cache"), 30},
46+
{:system, "CLOUD_CACHE_AWS_SECRET_ACCESS_KEY"},
47+
{:system, "AWS_SECRET_ACCESS_KEY"},
48+
:instance_role
49+
]
50+
end
51+
```
52+
1853
## Testing with LocalStack
1954

2055
`LocalStack` provides a fully functional local AWS cloud stack

config/config.exs

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,29 @@ import Config
22

33
if Mix.env() === :test do
44
config :cloud_cache, CloudCache.Adapters.S3,
5-
region: "us-west-1",
6-
sandbox_enabled: true,
7-
local_stack_enabled: false,
8-
http_client: CloudCache.Adapters.S3.HTTP,
9-
http_opts: [finch: CloudCache.Adapters.S3.Finch],
10-
retries: [
11-
max_attempts: 1,
12-
base_backoff_in_ms: 10,
13-
max_backoff_in_ms: 10_000
14-
],
15-
access_key_id: [
16-
{:awscli, System.get_env("AWS_PROFILE", "cloud_cache"), 30},
17-
{:system, "AWS_ACCESS_KEY_ID"}
18-
],
19-
secret_access_key: [
20-
{:awscli, System.get_env("AWS_PROFILE", "cloud_cache"), 30},
21-
{:system, "AWS_SECRET_ACCESS_KEY"}
22-
]
5+
auto_start: true,
6+
sandbox_enabled: true
237
else
248
config :cloud_cache, CloudCache.Adapters.S3,
25-
region: "us-west-1",
9+
auto_start: true,
2610
sandbox_enabled: false,
27-
local_stack_enabled: false,
28-
http_client: CloudCache.Adapters.S3.HTTP,
29-
http_opts: [finch: CloudCache.Adapters.S3.Finch],
3011
retries: [
3112
max_attempts: 10,
3213
base_backoff_in_ms: 10,
3314
max_backoff_in_ms: 10_000
3415
],
3516
access_key_id: [
17+
{:awscli, System.get_env("AWS_PROFILE", "default"), 30},
3618
{:awscli, System.get_env("AWS_PROFILE", "cloud_cache"), 30},
19+
{:system, "CLOUD_CACHE_AWS_ACCESS_KEY_ID"},
3720
{:system, "AWS_ACCESS_KEY_ID"},
38-
:instance_role,
39-
"<AWS_ACCESS_KEY_ID>"
21+
:instance_role
4022
],
4123
secret_access_key: [
24+
{:awscli, System.get_env("AWS_PROFILE", "default"), 30},
4225
{:awscli, System.get_env("AWS_PROFILE", "cloud_cache"), 30},
26+
{:system, "CLOUD_CACHE_AWS_SECRET_ACCESS_KEY"},
4327
{:system, "AWS_SECRET_ACCESS_KEY"},
44-
:instance_role,
45-
"<AWS_SECRET_ACCESS_KEY>"
28+
:instance_role
4629
]
4730
end

lib/cloud_cache.ex

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,18 @@ defmodule CloudCache do
66
77
## Usage
88
9-
Starting `CloudCache` is easy, just choose your adapter and run:
9+
CloudCache automatically starts the configured caches when the application
10+
starts. This means if you're using the default adapter, `CloudCache.Adapters.S3`,
11+
you don't need to do anything else.
12+
13+
If you want to start the caches manually then first set `auto_start` to `false`
14+
in your config:
15+
16+
```elixir
17+
config :cloud_cache, auto_start: false
18+
```
19+
20+
Then you can start `CloudCache` manually:
1021
1122
```elixir
1223
CloudCache.start_link([CloudCache.Adapters.S3])
@@ -71,13 +82,61 @@ defmodule CloudCache do
7182

7283
alias CloudCache.Adapter
7384

85+
@registry CloudCache.Registry
86+
@instances :instances
7487
@default_adapter CloudCache.Adapters.S3
7588
@default_name __MODULE__
7689

90+
@doc """
91+
Returns a list pids of all running instances.
92+
93+
### Examples
94+
95+
iex> CloudCache.instances()
96+
"""
97+
def instances do
98+
@registry
99+
|> Registry.lookup(@instances)
100+
|> Enum.map(fn {pid, _value} -> pid end)
101+
end
102+
103+
@doc """
104+
Returns the list of children for the given instance.
105+
106+
### Examples
107+
108+
iex> CloudCache.which_children()
109+
"""
110+
def which_children(name \\ @default_name) do
111+
Supervisor.which_children(name)
112+
end
113+
114+
@doc """
115+
Returns the pid of the instance with the given name.
116+
117+
### Examples
118+
119+
iex> CloudCache.whereis()
120+
"""
121+
def whereis(name \\ @default_name) do
122+
Process.whereis(name)
123+
end
124+
125+
@doc """
126+
Starts a new instance with the given caches and options.
127+
128+
### Examples
129+
130+
iex> CloudCache.start_link([CloudCache.Adapters.S3])
131+
"""
77132
def start_link(caches, opts \\ []) do
78-
Supervisor.start_link(__MODULE__, caches, Keyword.put_new(opts, :name, @default_name))
133+
{name, opts} = Keyword.pop(opts, :name, @default_name)
134+
Supervisor.start_link(__MODULE__, {name, caches}, Keyword.put(opts, :name, name))
79135
end
80136

137+
@doc """
138+
Returns a child specification for the given caches and options.
139+
"""
81140
def child_spec({caches, opts}) do
82141
%{
83142
id: {__MODULE__, opts[:id] || opts[:name] || opts[:key] || opts[:default]},
@@ -88,14 +147,26 @@ defmodule CloudCache do
88147
}
89148
end
90149

91-
def child_spec(opts) do
92-
opts |> Keyword.pop!(:caches) |> child_spec()
150+
def child_spec(list) do
151+
if Keyword.keyword?(list) do
152+
Keyword.pop!(list, :caches) |> child_spec()
153+
else
154+
child_spec({list, []})
155+
end
93156
end
94157

95158
@impl true
96-
def init(caches) do
159+
def init({name, caches}) do
160+
children = collect_children(caches)
161+
162+
case Registry.register(@registry, @instances, nil) do
163+
{:ok, _} -> Supervisor.init(children, strategy: :one_for_one)
164+
{:error, {:already_registered, _}} -> raise "instance already started: #{inspect(name)}"
165+
end
166+
end
167+
168+
defp collect_children(caches) do
97169
caches
98-
|> Kernel.++(CloudCache.Config.caches())
99170
|> Enum.map(fn
100171
{adapter, child_spec_args} -> {adapter, child_spec_args}
101172
adapter -> {adapter, []}
@@ -104,7 +175,6 @@ defmodule CloudCache do
104175
[adapter.child_spec(child_spec_args) | acc]
105176
end)
106177
|> Enum.reverse()
107-
|> Supervisor.init(strategy: :one_for_one)
108178
end
109179

110180
# Non-Multipart Upload API
@@ -115,6 +185,12 @@ defmodule CloudCache do
115185
|> Adapter.list_buckets(opts)
116186
end
117187

188+
def create_bucket(bucket, region, opts \\ []) do
189+
opts
190+
|> adapter()
191+
|> Adapter.create_bucket(bucket, region, opts)
192+
end
193+
118194
def list_objects(bucket, opts \\ []) do
119195
opts
120196
|> adapter()

lib/cloud_cache/adapter.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ defmodule CloudCache.Adapter do
1010

1111
@callback list_buckets(opts :: options()) :: {:ok, term()} | {:error, term()}
1212

13+
@callback create_bucket(bucket :: bucket(), region :: binary(), opts :: options()) ::
14+
{:ok, term()} | {:error, term()}
15+
1316
@callback head_object(
1417
bucket :: bucket(),
1518
object :: object(),
@@ -126,6 +129,10 @@ defmodule CloudCache.Adapter do
126129
adapter.list_buckets(opts)
127130
end
128131

132+
def create_bucket(adapter, bucket, region, opts \\ []) do
133+
adapter.create_bucket(bucket, region, opts)
134+
end
135+
129136
def head_object(adapter, bucket, object, opts \\ []) do
130137
adapter.head_object(bucket, object, opts)
131138
end

0 commit comments

Comments
 (0)