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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58eb0f80fe77ef64649d618a10effebcaf5faadb
4
- data.tar.gz: 100273def6d0617b57a299124d7ae2306a4ef19e
3
+ metadata.gz: a3e8d643dfca9cc2e978b9ecd7887fea9f5b3158
4
+ data.tar.gz: 25837935c927e4cf99d4cac355426a0ccec8d877
5
5
  SHA512:
6
- metadata.gz: 1ea464f973e823fca35892ada3d959c3354a1518b5bac24dca2d0a47cbd8162601a931b03bb774a20f2ffa429cce46f860ab3e45828e8325d473597d96d181c6
7
- data.tar.gz: d978a63436d6c3b8f7f79ff49909f5282edb33a5786c7b25ae1ce834e7595c9276031e17fe13ba19a5102db5693d9f439721e8cb0e384d5054b86e1953a361e0
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 = 5.minutes # default is 60 seconds
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
- # the Caddy requests are instant, and are up-to-date (as of 5 minutes ago, as specified above)
24
- # you could use this for high-level feature flags, cache dumping
25
- if Caddy[:flags][:fuzz_bizz] # Caddy provides a convenience method to access the cache by key; you can also access
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
- You need to start Caddy after fork:
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
- Similarly, after work boot:
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
- In the same vein, with developing with Spring, you need to have Caddy start after fork:
64
+ Start Caddy after fork:
63
65
 
64
66
  ```ruby
65
67
  # in your caddy.rb initializer, perhaps
@@ -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 magical auto-updating global cache.)
12
- s.summary = %q(Caddy gives you a magical auto-updating global cache.)
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&#45;&gt;App -->
39
+ <g id="edge1" class="edge"><title>Browser&#45;&gt;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&#45;&gt;Caddy -->
50
+ <g id="edge2" class="edge"><title>App&#45;&gt;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&#45;&gt;Etc. -->
61
+ <g id="edge5" class="edge"><title>Caddy&#45;&gt;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&#45;&gt;Database -->
72
+ <g id="edge3" class="edge"><title>Caddy&#45;&gt;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&#45;&gt;Slow Service -->
84
+ <g id="edge4" class="edge"><title>Caddy&#45;&gt;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>
@@ -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 @task.value
25
+ raise "Caddy cache access before initial load; allow some more time for your app to start up" unless @_cache
25
26
 
26
- @task.value
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
- ) { refresher.call }
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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Caddy
3
- VERSION = "1.0.0".freeze
3
+ VERSION = "1.0.1".freeze
4
4
  end
@@ -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
- Caddy.refresher = -> { sleep 5 }
66
- Caddy.refresh_interval = 1
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.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 magical auto-updating global cache.
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 magical auto-updating global cache.
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