cachext 0.4.1 → 0.4.2.pre.alpha1

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: ee15ce5861491a60920fd817fe166da8f8557474
4
- data.tar.gz: 99616c09308e8ca7d6f16fb02e2d4ae7cf3b0f60
3
+ metadata.gz: 26038adf65ec85eed32cecc1edd9385c11c68cc8
4
+ data.tar.gz: 7697ac15f9c7f5832915242a4a72375893780c25
5
5
  SHA512:
6
- metadata.gz: 7356cdc28341bae97bba42b150700ae065bc833acf0e77122c5aae55c36c9a81ca830414f5d58bf27a0e7d279c2adebd514d2b8b97cd3d11d004f297dad096d7
7
- data.tar.gz: 635116fce813c217dd61ce014f123db492f2c579f611b48238e739ca155bf2715f21e17d7323460af876cd85e127148b6448fe9197cbf1242ea5567dea49d018
6
+ metadata.gz: 408fcf3ed8969f0622edc7f594922c32419818126ee5f90ef86a933201d30c8ed954fda46c12f2e1fd5e413ca44b95839174455ce1248cbbad3c6f2bb0b6e31b
7
+ data.tar.gz: 448bfa70f2106b943a8ddd37de471b32642815fb0400f77ea739487dd4e568c95e10f99f8ca5092ee14f4005a9a91483af97253045754ccd2c862433b225318f
data/README.md CHANGED
@@ -8,6 +8,7 @@ Extensions to normal Rails caching:
8
8
 
9
9
  * Lock (inspired by https://github.com/seamusabshere/lock_and_cache)
10
10
  * Backup
11
+ * Circuit breaker
11
12
 
12
13
  ## Quickstart
13
14
 
@@ -119,6 +120,19 @@ Cachext.config.error_logger = nil
119
120
 
120
121
  If set to an object that responds to call, will `call` with any errors caught.
121
122
 
123
+ ```ruby
124
+ Cachext.config.failure_threshold = 3
125
+ ```
126
+
127
+ Number of tries before tripping circuit breaker.
128
+
129
+ ```ruby
130
+ Cachext.config.breaker_timeout = 60
131
+ ```
132
+
133
+ Time in seconds to wait before switching breaker to half-open.
134
+
135
+
122
136
  ## Usage
123
137
 
124
138
  ```ruby
@@ -129,11 +143,14 @@ Available options:
129
143
 
130
144
  * `expires_in`: override for the `default_expires_in`, in seconds
131
145
  * `default`: object or proc that will be used as the default if no backup is found
132
- * `errors`: override for the `default_errors` to be caught
133
- * `reraise_errors`: default `true`, if set to `false` NotFound errors will not
134
- be raised
135
- * `not_found_error`: override for `not_found_errors`
136
- * `heartbeat_expires`: override for `heartbeat_expires`
146
+ * `errors`: override for the `default_errors`: array of errors to catch and not reraise
147
+ * `reraise_errors`: default `true`, if set to `false` NotFound errors will not be raised
148
+ * `not_found_error`: (override) array of errors where we delete the backup and reraise
149
+ * `heartbeat_expires`: (override) time in seconds for process heardbeat to expire
150
+ * `failure_threshold`: (override) Number of tries before tripping circuit breaker
151
+ * `breaker_timeout`: (override) time in seconds to wait before switching breaker to half-open
152
+ * `cache`: use the first-level cache, defaults to true. If set to false, will always call the
153
+ fallback, but if an error is raised, will use the last known good value.
137
154
 
138
155
  ```ruby
139
156
  Cachext.multi key_base, ids, options, &block
@@ -15,17 +15,14 @@ Gem::Specification.new do |spec|
15
15
  spec.license = "MIT"
16
16
 
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
- spec.bindir = "exe"
19
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
18
  spec.require_paths = ["lib"]
21
19
 
22
- spec.add_dependency "activesupport", "~> 4.2"
20
+ spec.add_dependency "faraday"
23
21
  spec.add_dependency "redis"
24
- spec.add_dependency "redis-namespace"
25
22
  spec.add_dependency "redlock"
26
- spec.add_dependency "faraday"
27
23
  spec.add_dependency "dalli"
28
24
 
25
+ spec.add_development_dependency "activesupport"
29
26
  spec.add_development_dependency "bundler", "~> 1.10"
30
27
  spec.add_development_dependency "rake", "~> 10.0"
31
28
  spec.add_development_dependency "rspec"
@@ -1,5 +1,4 @@
1
1
  require "cachext/version"
2
- require "faraday/error"
3
2
 
4
3
  module Cachext
5
4
  autoload :Breaker, "cachext/breaker"
@@ -50,7 +49,12 @@ module Cachext
50
49
  end
51
50
 
52
51
  def self.configure &block
52
+ @config_block = block
53
53
  @config = Configuration.setup(&block)
54
54
  @client = Client.new @config
55
55
  end
56
+
57
+ def self.forked!
58
+ configure(&@config_block)
59
+ end
56
60
  end
@@ -21,9 +21,9 @@ module Cachext
21
21
  end
22
22
 
23
23
  def increment_failure
24
- redis.pipelined do
25
- redis.set key_str(:last_failure), Time.now.to_f
26
- redis.incr key_str(:monitor)
24
+ lock_redis.pipelined do
25
+ lock_redis.set key_str(:last_failure), Time.now.to_f
26
+ lock_redis.incr key_str(:monitor)
27
27
  end
28
28
  end
29
29
 
@@ -38,7 +38,7 @@ module Cachext
38
38
  end
39
39
 
40
40
  def reset!
41
- redis.del key_str(:monitor),
41
+ lock_redis.del key_str(:monitor),
42
42
  key_str(:health_check),
43
43
  key_str(:last_failure)
44
44
  end
@@ -62,27 +62,27 @@ module Cachext
62
62
  end
63
63
 
64
64
  def monitor
65
- redis.get(key_str(:monitor)).to_i
65
+ lock_redis.get(key_str(:monitor)).to_i
66
66
  end
67
67
 
68
68
  def last_failure
69
- lf = redis.get key_str(:last_failure)
69
+ lf = lock_redis.get key_str(:last_failure)
70
70
  lf.nil? ? nil : lf.to_f
71
71
  end
72
72
 
73
73
  def health_check
74
- redis.get(key_str(:health_check)).to_i
74
+ lock_redis.get(key_str(:health_check)).to_i
75
75
  end
76
76
 
77
77
  def increment_health_check
78
- redis.incr key_str(:health_check)
78
+ lock_redis.incr key_str(:health_check)
79
79
  end
80
80
 
81
81
  def key_str(name)
82
- "#{name}:#{key.raw.map(&:to_s).join(":")}"
82
+ "cachext:#{name}:#{key.raw.map(&:to_s).join(":")}"
83
83
  end
84
84
 
85
- def redis
85
+ def lock_redis
86
86
  config.lock_redis
87
87
  end
88
88
  end
@@ -50,7 +50,7 @@ module Cachext
50
50
  end
51
51
 
52
52
  def write key, fresh, options
53
- key.write fresh, expires_in: options.expires_in
53
+ key.write fresh, expires_in: options.expires_in if options.cache?
54
54
  end
55
55
  end
56
56
  end
@@ -1,6 +1,6 @@
1
1
  require "redlock"
2
- require "redis-namespace"
3
2
  require "thread"
3
+ require "faraday/error"
4
4
 
5
5
  module Cachext
6
6
  class Configuration
@@ -59,7 +59,7 @@ module Cachext
59
59
  end
60
60
 
61
61
  def lock_redis
62
- @lock_redis ||= Redis::Namespace.new :cachext, redis: redis
62
+ redis
63
63
  end
64
64
 
65
65
  def log_errors?
@@ -69,7 +69,7 @@ module Cachext
69
69
  def debug
70
70
  if block_given?
71
71
  if @debug
72
- @mutex.synchronize do
72
+ @debug_mutex.synchronize do
73
73
  yield
74
74
  end
75
75
  end
@@ -11,7 +11,9 @@ module Cachext
11
11
  def read key, options
12
12
  circuit = breaker.for(key)
13
13
  if circuit.open?
14
- key.read_backup
14
+ val = key.read_backup
15
+ debug_log { { m: :circuit_open, key: key, msg: "Circuit breaker open, reading from backup", val: val.inspect } }
16
+ val
15
17
  else
16
18
  circuit.check_health
17
19
  super
@@ -19,7 +19,7 @@ module Cachext
19
19
  end
20
20
 
21
21
  def call_block key, options, &block
22
- with_heartbeat_extender key.digest, options.heartbeat_expires do
22
+ with_heartbeat_extender key.lock_key, options.heartbeat_expires do
23
23
  super
24
24
  end
25
25
  end
@@ -46,17 +46,21 @@ module Cachext
46
46
  def obtain_lock key, options
47
47
  start_time = Time.now
48
48
 
49
- until lock_info = @config.lock_manager.lock(key.digest, (options.heartbeat_expires * 1000).ceil)
50
- wait_for_lock key, start_time
49
+ until lock_info ||= @config.lock_manager.lock(key.lock_key, (options.heartbeat_expires * 1000).ceil)
50
+ if wait_for_lock(key, start_time) == :timeout
51
+ lock_info = @config.lock_manager.lock(key.lock_key, (options.heartbeat_expires * 1000).ceil)
52
+ raise TimeoutWaitingForLock unless lock_info
53
+ end
51
54
  end
52
55
 
53
56
  lock_info
54
57
  end
55
58
 
56
59
  def wait_for_lock key, start_time
57
- sleep rand(0..(@config.max_lock_wait / 2))
60
+ sleep rand(0.01..0.02)
61
+
58
62
  if Time.now - start_time > @config.max_lock_wait
59
- raise TimeoutWaitingForLock
63
+ :timeout
60
64
  end
61
65
  end
62
66
  end
@@ -19,8 +19,12 @@ module Cachext
19
19
  [:backup_cache] + raw
20
20
  end
21
21
 
22
+ def lock_key
23
+ "cachext:lock:#{digest}"
24
+ end
25
+
22
26
  def locked?
23
- lock_redis.exists digest
27
+ lock_redis.exists lock_key
24
28
  end
25
29
 
26
30
  def read
@@ -106,7 +106,7 @@ module Cachext
106
106
 
107
107
  def lock_key_from_ids(ids)
108
108
  key = Key.new multi.key_base + ids
109
- key.digest
109
+ key.lock_key
110
110
  end
111
111
 
112
112
  def write_cache records
@@ -1,3 +1,3 @@
1
1
  module Cachext
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2-alpha1"
3
3
  end
metadata CHANGED
@@ -1,31 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cachext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2.pre.alpha1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Donald Plummer
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-18 00:00:00.000000000 Z
11
+ date: 2017-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '4.2'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '4.2'
27
- - !ruby/object:Gem::Dependency
28
- name: redis
14
+ name: faraday
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - ">="
@@ -39,7 +25,7 @@ dependencies:
39
25
  - !ruby/object:Gem::Version
40
26
  version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
- name: redis-namespace
28
+ name: redis
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
@@ -67,7 +53,7 @@ dependencies:
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
- name: faraday
56
+ name: dalli
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - ">="
@@ -81,13 +67,13 @@ dependencies:
81
67
  - !ruby/object:Gem::Version
82
68
  version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
- name: dalli
70
+ name: activesupport
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - ">="
88
74
  - !ruby/object:Gem::Version
89
75
  version: '0'
90
- type: :runtime
76
+ type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
@@ -226,9 +212,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
226
212
  version: '0'
227
213
  required_rubygems_version: !ruby/object:Gem::Requirement
228
214
  requirements:
229
- - - ">="
215
+ - - ">"
230
216
  - !ruby/object:Gem::Version
231
- version: '0'
217
+ version: 1.3.1
232
218
  requirements: []
233
219
  rubyforge_project:
234
220
  rubygems_version: 2.5.1