caddy 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -10
- data/caddy.gemspec +2 -2
- data/docs/architecture.dot +40 -0
- data/docs/architecture.svg +90 -0
- data/lib/caddy.rb +11 -3
- data/lib/caddy/version.rb +1 -1
- data/test/caddy_test.rb +37 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3e8d643dfca9cc2e978b9ecd7887fea9f5b3158
|
4
|
+
data.tar.gz: 25837935c927e4cf99d4cac355426a0ccec8d877
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05ccf0297987d26658f8cd331d750357a92fa6f8258c462a18697e69552e99eff13df4bd33953bfebd27a17f64b5cff2cd1a5bd07f1d4c986a34c657d5f6adae
|
7
|
+
data.tar.gz: 6527ac465c99634d5eec1eb2f195f7c92fe58d6d310a6b84a4f5bca12975cfd54bdd0b88e053970e5a74f862b1ecf10272a5ea2b9fdb9cfa469df304ed26979e
|
data/README.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# Caddy [![Build Status](https://travis-ci.org/nickelser/caddy.svg?branch=master)](https://travis-ci.org/nickelser/caddy) [![Code Climate](https://codeclimate.com/github/nickelser/caddy/badges/gpa.svg)](https://codeclimate.com/github/nickelser/caddy) [![Test Coverage](https://codeclimate.com/github/nickelser/caddy/badges/coverage.svg)](https://codeclimate.com/github/nickelser/caddy) [![Gem Version](https://badge.fury.io/rb/caddy.svg)](http://badge.fury.io/rb/caddy)
|
2
2
|
|
3
|
-
Caddy is an asynchronously updated store that is updated on an interval to store objects that you can access quickly during requests. The cache refresher function can be as slow as you would like and it will not affect your request-time performance.
|
3
|
+
Caddy is an asynchronously updated store that is updated on an interval to store objects that you can access quickly during requests. The cache refresher function can be as slow as you would like and it will not affect your request-time performance. Caddy is great for storing information like feature flags -- accessed extremely frequently during many requests, updated very rarely and usually safe to be stale by some amount.
|
4
4
|
|
5
5
|
It's powered by [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby), a battle-tested and comprehensive thread-based (& thread-safe) concurrency library.
|
6
6
|
|
7
|
+
![Architecture Diagram](https://rawgit.com/nickelser/caddy/master/docs/architecture.svg)
|
8
|
+
|
7
9
|
```ruby
|
8
10
|
# in your initializers (caddy.rb would be a wonderful name)
|
9
11
|
Caddy.refresher = lambda do
|
@@ -13,17 +15,17 @@ Caddy.refresher = lambda do
|
|
13
15
|
}
|
14
16
|
end
|
15
17
|
|
16
|
-
Caddy.refresh_interval =
|
18
|
+
Caddy.refresh_interval = 30.seconds # default is 60 seconds; the actual amount is smoothed slightly
|
19
|
+
# to avoid a stampeding herd of refreshes
|
17
20
|
|
18
|
-
# ... after your application forks
|
21
|
+
# ... after your application forks (see the guide below for Unicorn, Puma & Spring)
|
19
22
|
Caddy.start
|
20
23
|
|
21
24
|
# ... in a controller
|
22
25
|
def index
|
23
|
-
#
|
24
|
-
#
|
25
|
-
if Caddy[:flags][:fuzz_bizz]
|
26
|
-
# it directly with Caddy.cache[:flags][...]
|
26
|
+
# Caddy provides a convenience method to access the cache by key; you can also access
|
27
|
+
# what your refresher returns directly with Caddy.cache[:flags][...]
|
28
|
+
if Caddy[:flags][:fuzz_bizz]
|
27
29
|
Rails.cache.fetch("#{Caddy[:cache_keys][:global_key]}/#{Caddy[:cache_keys][:index_key]}/foo/bar") do
|
28
30
|
# wonderful things happen here
|
29
31
|
end
|
@@ -33,7 +35,7 @@ end
|
|
33
35
|
|
34
36
|
## Using Caddy with Unicorn
|
35
37
|
|
36
|
-
|
38
|
+
Start Caddy after fork:
|
37
39
|
|
38
40
|
```ruby
|
39
41
|
# in your unicorn.rb initializer
|
@@ -46,7 +48,7 @@ end
|
|
46
48
|
|
47
49
|
## Using Caddy with Puma
|
48
50
|
|
49
|
-
|
51
|
+
Start Caddy after the worker boots:
|
50
52
|
|
51
53
|
```ruby
|
52
54
|
# in your puma.rb initializer
|
@@ -59,7 +61,7 @@ end
|
|
59
61
|
|
60
62
|
## Using Caddy with Spring
|
61
63
|
|
62
|
-
|
64
|
+
Start Caddy after fork:
|
63
65
|
|
64
66
|
```ruby
|
65
67
|
# in your caddy.rb initializer, perhaps
|
data/caddy.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.version = Caddy::VERSION
|
9
9
|
s.authors = ["Nick Elser"]
|
10
10
|
s.email = ["nick.elser@gmail.com"]
|
11
|
-
s.description = %q(Caddy gives you a
|
12
|
-
s.summary = %q(Caddy gives you a
|
11
|
+
s.description = %q(Caddy gives you a auto-updating global cache to speed up requests.)
|
12
|
+
s.summary = %q(Caddy gives you a auto-updating global cache to speed up requests.)
|
13
13
|
s.homepage = "http://github.com/nickelser/caddy"
|
14
14
|
s.licenses = ["MIT"]
|
15
15
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
digraph G {
|
2
|
+
label="Caddy Architecture"
|
3
|
+
labelloc="top"
|
4
|
+
fontsize=20
|
5
|
+
graph [label="kudos to sferik for the diagram", labelloc=b, labeljust=r, fontsize=10]
|
6
|
+
fontname="Helvetica Neue"
|
7
|
+
node [shape="ellipse", style="filled", fontname="Helvetica Neue"]
|
8
|
+
edge [fontname="Helvetica Neue"]
|
9
|
+
peripheries=0
|
10
|
+
rankdir="LR"
|
11
|
+
subgraph clusterClient {
|
12
|
+
bgcolor="#d0c0a0"
|
13
|
+
fontsize=16
|
14
|
+
label="Client"
|
15
|
+
Browser
|
16
|
+
}
|
17
|
+
subgraph clusterServer {
|
18
|
+
bgcolor="#d0c0a0"
|
19
|
+
fontsize=16
|
20
|
+
label="Server"
|
21
|
+
subgraph clusterApp {
|
22
|
+
bgcolor="#b02b2c"
|
23
|
+
label="Ruby Process"
|
24
|
+
App
|
25
|
+
subgraph clusterCaddy {
|
26
|
+
bgcolor="#b02b2c"
|
27
|
+
label=""
|
28
|
+
Caddy
|
29
|
+
}
|
30
|
+
}
|
31
|
+
"Etc."
|
32
|
+
Database
|
33
|
+
"Slow Service"
|
34
|
+
}
|
35
|
+
Browser -> App [dir="both"]
|
36
|
+
App -> Caddy [dir="both"]
|
37
|
+
Caddy -> Database [label="Async Refresh", style="dotted", dir="both"]
|
38
|
+
Caddy -> "Slow Service" [style="dotted", dir="both"]
|
39
|
+
Caddy -> "Etc." [style="dotted", dir="both"]
|
40
|
+
}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
3
|
+
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
4
|
+
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
|
5
|
+
-->
|
6
|
+
<!-- Title: G Pages: 1 -->
|
7
|
+
<svg width="615pt" height="231pt"
|
8
|
+
viewBox="0.00 0.00 614.94 230.93" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
9
|
+
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 226.93)">
|
10
|
+
<title>G</title>
|
11
|
+
<polygon fill="white" stroke="none" points="-4,4 -4,-226.93 610.937,-226.93 610.937,4 -4,4"/>
|
12
|
+
<text text-anchor="middle" x="530.497" y="-7.92993" font-family="Helvetica Neue" font-size="10.00">kudos to sferik for the diagram</text>
|
13
|
+
<g id="clust1" class="cluster"><title>clusterClient</title>
|
14
|
+
<polygon fill="#d0c0a0" stroke="none" points="8,-81.9299 8,-160.93 117.241,-160.93 117.241,-81.9299 8,-81.9299"/>
|
15
|
+
<text text-anchor="middle" x="88.6492" y="-92.2178" font-family="Helvetica Neue" font-size="16.00">Client</text>
|
16
|
+
</g>
|
17
|
+
<g id="clust2" class="cluster"><title>clusterServer</title>
|
18
|
+
<polygon fill="#d0c0a0" stroke="none" points="136.241,-27.9299 136.241,-214.93 598.937,-214.93 598.937,-27.9299 136.241,-27.9299"/>
|
19
|
+
<text text-anchor="middle" x="567.833" y="-38.2178" font-family="Helvetica Neue" font-size="16.00">Server</text>
|
20
|
+
</g>
|
21
|
+
<g id="clust3" class="cluster"><title>clusterApp</title>
|
22
|
+
<polygon fill="#b02b2c" stroke="none" points="144.241,-73.9299 144.241,-168.93 341.204,-168.93 341.204,-73.9299 144.241,-73.9299"/>
|
23
|
+
<text text-anchor="middle" x="283.42" y="-84.2178" font-family="Helvetica Neue" font-size="16.00">Ruby Process</text>
|
24
|
+
</g>
|
25
|
+
<g id="clust4" class="cluster"><title>clusterCaddy</title>
|
26
|
+
<polygon fill="#b02b2c" stroke="none" points="238.532,-108.93 238.532,-160.93 333.204,-160.93 333.204,-108.93 238.532,-108.93"/>
|
27
|
+
</g>
|
28
|
+
<!-- Browser -->
|
29
|
+
<g id="node1" class="node"><title>Browser</title>
|
30
|
+
<ellipse fill="lightgrey" stroke="black" cx="62.6206" cy="-134.93" rx="46.7415" ry="18"/>
|
31
|
+
<text text-anchor="middle" x="62.6206" y="-132.081" font-family="Helvetica Neue" font-size="14.00">Browser</text>
|
32
|
+
</g>
|
33
|
+
<!-- App -->
|
34
|
+
<g id="node2" class="node"><title>App</title>
|
35
|
+
<ellipse fill="lightgrey" stroke="black" cx="180.887" cy="-134.93" rx="28.7915" ry="18"/>
|
36
|
+
<text text-anchor="middle" x="180.887" y="-132.081" font-family="Helvetica Neue" font-size="14.00">App</text>
|
37
|
+
</g>
|
38
|
+
<!-- Browser->App -->
|
39
|
+
<g id="edge1" class="edge"><title>Browser->App</title>
|
40
|
+
<path fill="none" stroke="black" d="M119.781,-134.93C127.305,-134.93 134.874,-134.93 141.981,-134.93"/>
|
41
|
+
<polygon fill="black" stroke="black" points="119.572,-131.43 109.572,-134.93 119.572,-138.43 119.572,-131.43"/>
|
42
|
+
<polygon fill="black" stroke="black" points="142.006,-138.43 152.006,-134.93 142.006,-131.43 142.006,-138.43"/>
|
43
|
+
</g>
|
44
|
+
<!-- Caddy -->
|
45
|
+
<g id="node3" class="node"><title>Caddy</title>
|
46
|
+
<ellipse fill="lightgrey" stroke="black" cx="285.868" cy="-134.93" rx="39.1731" ry="18"/>
|
47
|
+
<text text-anchor="middle" x="285.868" y="-132.081" font-family="Helvetica Neue" font-size="14.00">Caddy</text>
|
48
|
+
</g>
|
49
|
+
<!-- App->Caddy -->
|
50
|
+
<g id="edge2" class="edge"><title>App->Caddy</title>
|
51
|
+
<path fill="none" stroke="black" d="M219.873,-134.93C225.096,-134.93 230.519,-134.93 235.904,-134.93"/>
|
52
|
+
<polygon fill="black" stroke="black" points="219.755,-131.43 209.755,-134.93 219.755,-138.43 219.755,-131.43"/>
|
53
|
+
<polygon fill="black" stroke="black" points="236.153,-138.43 246.153,-134.93 236.153,-131.43 236.153,-138.43"/>
|
54
|
+
</g>
|
55
|
+
<!-- Etc. -->
|
56
|
+
<g id="node4" class="node"><title>Etc.</title>
|
57
|
+
<ellipse fill="lightgrey" stroke="black" cx="524.186" cy="-80.9299" rx="27.5032" ry="18"/>
|
58
|
+
<text text-anchor="middle" x="524.186" y="-78.0809" font-family="Helvetica Neue" font-size="14.00">Etc.</text>
|
59
|
+
</g>
|
60
|
+
<!-- Caddy->Etc. -->
|
61
|
+
<g id="edge5" class="edge"><title>Caddy->Etc.</title>
|
62
|
+
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M331.509,-124.729C376.766,-114.388 445.897,-98.5908 487.596,-89.0624"/>
|
63
|
+
<polygon fill="black" stroke="black" points="330.453,-121.38 321.484,-127.02 332.012,-128.204 330.453,-121.38"/>
|
64
|
+
<polygon fill="black" stroke="black" points="488.606,-92.4219 497.575,-86.7821 487.047,-85.5978 488.606,-92.4219"/>
|
65
|
+
</g>
|
66
|
+
<!-- Database -->
|
67
|
+
<g id="node5" class="node"><title>Database</title>
|
68
|
+
<ellipse fill="lightgrey" stroke="black" cx="524.186" cy="-134.93" rx="51.9801" ry="18"/>
|
69
|
+
<text text-anchor="middle" x="524.186" y="-132.081" font-family="Helvetica Neue" font-size="14.00">Database</text>
|
70
|
+
</g>
|
71
|
+
<!-- Caddy->Database -->
|
72
|
+
<g id="edge3" class="edge"><title>Caddy->Database</title>
|
73
|
+
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M335.614,-134.93C372.208,-134.93 422.562,-134.93 461.885,-134.93"/>
|
74
|
+
<polygon fill="black" stroke="black" points="335.363,-131.43 325.363,-134.93 335.363,-138.43 335.363,-131.43"/>
|
75
|
+
<polygon fill="black" stroke="black" points="461.887,-138.43 471.887,-134.93 461.887,-131.43 461.887,-138.43"/>
|
76
|
+
<text text-anchor="middle" x="394.319" y="-140.432" font-family="Helvetica Neue" font-size="14.00">Async Refresh</text>
|
77
|
+
</g>
|
78
|
+
<!-- Slow Service -->
|
79
|
+
<g id="node6" class="node"><title>Slow Service</title>
|
80
|
+
<ellipse fill="lightgrey" stroke="black" cx="524.186" cy="-188.93" rx="66.5035" ry="18"/>
|
81
|
+
<text text-anchor="middle" x="524.186" y="-186.081" font-family="Helvetica Neue" font-size="14.00">Slow Service</text>
|
82
|
+
</g>
|
83
|
+
<!-- Caddy->Slow Service -->
|
84
|
+
<g id="edge4" class="edge"><title>Caddy->Slow Service</title>
|
85
|
+
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M326.611,-149.224C334.064,-151.646 341.83,-153.998 349.204,-155.93 383.957,-165.033 423.233,-172.702 455.662,-178.349"/>
|
86
|
+
<polygon fill="black" stroke="black" points="327.647,-145.88 317.053,-146.03 325.428,-152.519 327.647,-145.88"/>
|
87
|
+
<polygon fill="black" stroke="black" points="455.489,-181.87 465.936,-180.11 456.672,-174.97 455.489,-181.87"/>
|
88
|
+
</g>
|
89
|
+
</g>
|
90
|
+
</svg>
|
data/lib/caddy.rb
CHANGED
@@ -14,6 +14,7 @@ module Caddy
|
|
14
14
|
@task = nil
|
15
15
|
@refresh_interval = DEFAULT_REFRESH_INTERVAL
|
16
16
|
@_started_pid = nil
|
17
|
+
@_cache = nil
|
17
18
|
|
18
19
|
def self.[](k)
|
19
20
|
cache[k]
|
@@ -21,9 +22,9 @@ module Caddy
|
|
21
22
|
|
22
23
|
def self.cache
|
23
24
|
raise "Please run `Caddy.start` before attempting to access the cache" unless @task
|
24
|
-
raise "Caddy cache access before initial load; allow some more time for your app to start up" unless @
|
25
|
+
raise "Caddy cache access before initial load; allow some more time for your app to start up" unless @_cache
|
25
26
|
|
26
|
-
@
|
27
|
+
@_cache
|
27
28
|
end
|
28
29
|
|
29
30
|
def self.start
|
@@ -47,7 +48,14 @@ module Caddy
|
|
47
48
|
run_now: true,
|
48
49
|
execution_interval: interval,
|
49
50
|
timeout_interval: timeout_interval
|
50
|
-
)
|
51
|
+
) do
|
52
|
+
begin
|
53
|
+
@_cache = refresher.call
|
54
|
+
@_cache.freeze if @_cache.respond_to?(:freeze)
|
55
|
+
rescue
|
56
|
+
raise
|
57
|
+
end
|
58
|
+
end
|
51
59
|
|
52
60
|
@task.add_observer(Caddy::TaskObserver.new)
|
53
61
|
@task.execute
|
data/lib/caddy/version.rb
CHANGED
data/test/caddy_test.rb
CHANGED
@@ -6,6 +6,7 @@ class CaddyTest < Minitest::Test
|
|
6
6
|
Caddy.refresher = -> {}
|
7
7
|
Caddy.refresh_interval = 30
|
8
8
|
Caddy.error_handler = nil
|
9
|
+
sleep(0.05)
|
9
10
|
end
|
10
11
|
|
11
12
|
def test_basic_lookup
|
@@ -29,12 +30,27 @@ class CaddyTest < Minitest::Test
|
|
29
30
|
assert_operator Caddy[:baz], :>=, 2
|
30
31
|
end
|
31
32
|
|
33
|
+
def test_stale_value
|
34
|
+
ran_once = false
|
35
|
+
Caddy.refresher = lambda do
|
36
|
+
raise "boom" if ran_once
|
37
|
+
ran_once = true
|
38
|
+
{baz: "bizz"}
|
39
|
+
end
|
40
|
+
Caddy.refresh_interval = 2
|
41
|
+
Caddy.start
|
42
|
+
sleep(3)
|
43
|
+
|
44
|
+
assert_equal "bizz", Caddy[:baz]
|
45
|
+
end
|
46
|
+
|
32
47
|
def test_restart
|
33
48
|
Caddy.refresher = -> { {foo: "baz"} }
|
34
49
|
Caddy.start
|
35
50
|
sleep(0.1)
|
36
51
|
Caddy.stop
|
37
52
|
Caddy.restart
|
53
|
+
sleep(0.1)
|
38
54
|
|
39
55
|
assert_equal "baz", Caddy[:foo]
|
40
56
|
end
|
@@ -53,23 +69,42 @@ class CaddyTest < Minitest::Test
|
|
53
69
|
Caddy.refresher = -> { raise "boom" }
|
54
70
|
Caddy.error_handler = -> (_) { raise "boomboom" }
|
55
71
|
Caddy.start
|
72
|
+
sleep(0.1)
|
56
73
|
end
|
57
74
|
|
58
75
|
def test_bad_error_handler
|
59
76
|
Caddy.refresher = -> { raise "boom" }
|
60
77
|
Caddy.error_handler = "no"
|
61
78
|
Caddy.start
|
79
|
+
sleep(0.1)
|
62
80
|
end
|
63
81
|
|
64
82
|
def test_timeout
|
65
|
-
|
66
|
-
Caddy.
|
83
|
+
timed_out = nil
|
84
|
+
Caddy.refresher = -> { sleep 1 }
|
85
|
+
Caddy.error_handler = -> (ex) { timed_out = ex }
|
86
|
+
Caddy.refresh_interval = 0.5
|
67
87
|
Caddy.start
|
88
|
+
sleep(2)
|
89
|
+
|
90
|
+
assert_kind_of Concurrent::TimeoutError, timed_out
|
91
|
+
Caddy.stop
|
92
|
+
sleep(2)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_no_handler_timeout
|
96
|
+
Caddy.refresher = -> { sleep 1 }
|
97
|
+
Caddy.refresh_interval = 0.5
|
98
|
+
Caddy.start
|
99
|
+
sleep(2)
|
100
|
+
Caddy.stop
|
101
|
+
sleep(2)
|
68
102
|
end
|
69
103
|
|
70
104
|
def test_no_handler
|
71
105
|
Caddy.refresher = -> { raise "boom" }
|
72
106
|
Caddy.start
|
107
|
+
sleep(0.1)
|
73
108
|
end
|
74
109
|
|
75
110
|
def test_requires_refesher
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: caddy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Elser
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 0.4.7
|
69
|
-
description: Caddy gives you a
|
69
|
+
description: Caddy gives you a auto-updating global cache to speed up requests.
|
70
70
|
email:
|
71
71
|
- nick.elser@gmail.com
|
72
72
|
executables: []
|
@@ -82,6 +82,8 @@ files:
|
|
82
82
|
- README.md
|
83
83
|
- Rakefile
|
84
84
|
- caddy.gemspec
|
85
|
+
- docs/architecture.dot
|
86
|
+
- docs/architecture.svg
|
85
87
|
- lib/caddy.rb
|
86
88
|
- lib/caddy/task_observer.rb
|
87
89
|
- lib/caddy/version.rb
|
@@ -110,7 +112,7 @@ rubyforge_project:
|
|
110
112
|
rubygems_version: 2.5.1
|
111
113
|
signing_key:
|
112
114
|
specification_version: 4
|
113
|
-
summary: Caddy gives you a
|
115
|
+
summary: Caddy gives you a auto-updating global cache to speed up requests.
|
114
116
|
test_files:
|
115
117
|
- test/caddy_test.rb
|
116
118
|
- test/test_helper.rb
|