background_cache 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -3,62 +3,79 @@ BackgroundCache
3
3
 
4
4
  Bust caches before your users do (in your Rails app).
5
5
 
6
+ Works with [memcache-client](https://github.com/mperham/memcache-client), [Dalli](https://github.com/mperham/dalli), or [memcached](https://github.com/fauna/memcached).
7
+
6
8
  Requirements
7
9
  ------------
8
10
 
9
- <pre>
10
- sudo gem install background_cache
11
- </pre>
12
-
13
- ### config/environment.rb
14
-
15
- <pre>
16
- config.gem 'background_cache'
17
- </pre>
11
+ gem install background_cache
18
12
 
19
13
  Dynamic Configuration
20
14
  ---------------------
21
15
 
22
- Create *lib/background\_cache\_config.rb*:
16
+ Create `lib/background_cache_config.rb` in your Rails app:
23
17
 
24
- <pre>
25
- BackgroundCache::Config.new do
18
+ BackgroundCache::Config.new do
26
19
 
27
- # Configure a background cache in one call
28
-
29
- Tag::League.find(:all).each do |tag|
30
- cache(
31
- # Route params
32
- :controller => 'sections',
33
- :action => 'teams',
34
- :tag => tag.permalink,
20
+ # Configure using block methods
35
21
 
36
- # Background cache options
37
- :group => 'every_hour',
38
- :layout => false,
39
- :only => "sections_teams_#{tag.permalink}"
40
- )
41
- end
42
-
43
- # Configure using block methods
44
-
45
- group('every_hour').layout(false).only("sections_teams_#{tag.permalink}") do
46
- Tag::League.find(:all).each do |tag|
47
- cache("/#{tag.permalink}")
48
- end
49
- end
50
- end
51
- </pre>
22
+ group('every_hour').layout(false).only("sections_teams_#{tag.permalink}") do
23
+ Tag::League.find(:all).each do |tag|
24
+ cache(:path => "/#{tag.permalink}")
25
+ end
26
+ end
52
27
 
53
- The <code>cache</code> method takes route parameters or a path.
28
+ # Configure using options
29
+
30
+ Tag::League.find(:all).each do |tag|
31
+ cache(
32
+ # Route params
33
+ :controller => 'sections',
34
+ :action => 'teams',
35
+ :tag => tag.permalink,
54
36
 
55
- The <code>only</code> and <code>except</code> methods/options take fragment ids or arrays of fragment ids.
37
+ # Or specify a path
38
+ :path => "/#{tag.permalink}",
39
+
40
+ # Background cache options
41
+ :group => 'every_hour',
42
+ :layout => false,
43
+ :only => "sections_teams_#{tag.permalink}"
44
+ )
45
+ end
46
+ end
47
+
48
+ The `only` and `except` options take cache fragment ids or arrays of cache fragment ids.
56
49
 
57
50
  If no fragment is specified, all of the action's caches will regenerate.
58
51
 
59
- Rake task
52
+ Rake Task
60
53
  ---------
61
54
 
62
- Add <code>rake background_cache</code> to cron. All cache configurations are busted every time it is run.
55
+ Add `rake background_cache` to cron. All cache configurations are busted every time it is run.
56
+
57
+ To run a specific group of caches, run `rake background_cache[every_hour]` (as per the example above).
58
+
59
+ Daemon Mode
60
+ -----------
61
+
62
+ Create `config/background_cache.yml` in your Rails app:
63
+
64
+ redis: localhost:6379/0
65
+
66
+ Start a `background_cache` daemon from your Rails app:
67
+
68
+ $ cd path/to/app
69
+ $ background_cache
70
+
71
+ Run caches via Ruby:
72
+
73
+ require 'background_cache'
74
+
75
+ client = BackgroundCache::Client.new('/path/to/app')
76
+
77
+ # Cache group
78
+ client.cache(:group => "every_hour")
63
79
 
64
- To run a specific group of caches, run <code>rake background\_cache[every\_hour]</code> (as per the example above).
80
+ # Manual cache
81
+ client.cache(:path => "/")
@@ -6,7 +6,7 @@ $:.unshift lib unless $:.include?(lib)
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "background_cache"
9
- s.version = '0.1.4'
9
+ s.version = '0.2.0'
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.authors = [ "Winton Welsh" ]
12
12
  s.email = [ "mail@wintoni.us" ]
@@ -22,4 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency "rack-test", "= 0.5.3"
23
23
  s.add_development_dependency "rails", "= 2.3.10"
24
24
  s.add_development_dependency "rspec", "~> 1.0"
25
+
26
+ s.add_dependency "redis", "~> 2.2.2"
27
+ s.add_dependency "yajl-ruby", "~> 1.0.0"
25
28
  end
data/bin/background_cache CHANGED
@@ -1,3 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require File.expand_path("../../lib/background_cache", __FILE__)
3
+ require File.expand_path("../../lib/background_cache/daemon", __FILE__)
4
+
5
+ BackgroundCache::Daemon.new(Dir.pwd)
@@ -0,0 +1,46 @@
1
+ module BackgroundCache
2
+ class Client
3
+
4
+ attr_reader :redis_1, :redis_2
5
+
6
+ def initialize(root)
7
+ if File.exists?(yaml = "#{root}/config/background_cache.yml")
8
+ options = YAML.load(File.read(yaml))
9
+ else
10
+ puts "\nFAIL: config/background_cache.yml not found"
11
+ shutdown
12
+ end
13
+
14
+ @redis_1 = Redis.connect(:url => "redis://#{options['redis']}")
15
+ @redis_2 = Redis.connect(:url => "redis://#{options['redis']}")
16
+ end
17
+
18
+ def cache(options)
19
+ wait = options.delete(:wait)
20
+ subscribe_to = options[:channel] = Digest::SHA1.hexdigest("#{rand}")
21
+ options = Yajl::Encoder.encode(options)
22
+ response = nil
23
+
24
+ if wait != false
25
+ Timeout.timeout(60) do
26
+ @redis_1.subscribe("background_cache:response:#{subscribe_to}") do |on|
27
+ on.subscribe do |channel, subscriptions|
28
+ @redis_2.rpush "background_cache:request", options
29
+ end
30
+
31
+ on.message do |channel, message|
32
+ if message.include?('[SUCCESS]')
33
+ response = true
34
+ @redis_1.unsubscribe
35
+ end
36
+ end
37
+ end
38
+ end
39
+ else
40
+ @redis_1.rpush "background_cache:request", options
41
+ end
42
+
43
+ response
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,89 @@
1
+ require 'rubygems'
2
+
3
+ require "digest/sha1"
4
+ require "timeout"
5
+ require "yaml"
6
+
7
+ gem "yajl-ruby", "~> 1.0.0"
8
+ require "yajl"
9
+
10
+ gem "redis", "~> 2.2.2"
11
+ require "redis"
12
+
13
+ module BackgroundCache
14
+ class Daemon
15
+
16
+ def initialize(root)
17
+ if File.exists?(yaml = "#{root}/config/background_cache.yml")
18
+ options = YAML.load(File.read(yaml))
19
+ else
20
+ puts "\nFAIL: config/background_cache.yml not found"
21
+ shutdown
22
+ end
23
+
24
+ puts "\nStarting background cache server (redis @ #{options['redis']})..."
25
+
26
+ require "#{root}/config/environment.rb"
27
+ require File.expand_path("../../background_cache", __FILE__)
28
+
29
+ instance = BackgroundCache.boot
30
+ redis = Redis.connect(:url => "redis://#{options['redis']}")
31
+ retries = 0
32
+
33
+ begin
34
+ while true
35
+ request = redis.lpop('background_cache:request')
36
+ if request
37
+ Timeout.timeout(60) do
38
+ request = Yajl::Parser.parse(request)
39
+ channel = request.delete('channel')
40
+
41
+ cache_key = request.to_a.sort { |a, b| a.first <=> b.first }.inspect
42
+
43
+ request.keys.each do |key|
44
+ request[(key.to_sym rescue key) || key] = request.delete(key)
45
+ end
46
+
47
+ unless redis.get(cache_key)
48
+ redis.set(cache_key, 1)
49
+
50
+ # Timeout incase execution fails
51
+ redis.expire(cache_key, 5 * 60)
52
+
53
+ if request[:group]
54
+ BackgroundCache.cache!(request[:group], instance)
55
+ else
56
+ BackgroundCache.manual(
57
+ BackgroundCache::Config.build_cache(request),
58
+ instance
59
+ )
60
+ end
61
+
62
+ redis.del(cache_key)
63
+ redis.publish(
64
+ "background_cache:response:#{channel}",
65
+ "[SUCCESS]"
66
+ )
67
+ end
68
+ end
69
+ end
70
+
71
+ sleep(1.0 / 1000.0)
72
+ end
73
+ rescue Interrupt
74
+ shut_down
75
+ rescue Exception => e
76
+ puts "\nError: #{e.message}"
77
+ puts "\t#{e.backtrace.join("\n\t")}"
78
+ retries += 1
79
+ shut_down if retries >= 10
80
+ retry
81
+ end
82
+ end
83
+
84
+ def shut_down
85
+ puts "\nShutting down background cache server..."
86
+ exit
87
+ end
88
+ end
89
+ end
@@ -1,10 +1,20 @@
1
+ require 'rubygems'
2
+
1
3
  gem 'rack-test', '=0.5.3'
2
4
 
5
+ gem "yajl-ruby", "~> 1.0.0"
6
+ require "yajl"
7
+
8
+ gem "redis", "~> 2.2.2"
9
+ require "redis"
10
+
3
11
  require 'digest/sha2'
4
12
  require 'rack/test'
13
+ require 'yaml'
5
14
 
6
15
  $:.unshift File.dirname(__FILE__)
7
16
 
17
+ require 'background_cache/client'
8
18
  require 'background_cache/config'
9
19
  require 'background_cache/controller'
10
20
  require 'background_cache/helper'
@@ -24,8 +34,10 @@ module BackgroundCache
24
34
  BackgroundCache::Config.current_cache
25
35
  end
26
36
 
27
- def self.cache!(group=nil)
28
- instance = self.boot
37
+ def self.cache!(group=nil, instance=nil)
38
+ unless instance
39
+ instance = self.boot
40
+ end
29
41
  BackgroundCache::Config.load!(group)
30
42
  caches = BackgroundCache::Config.caches
31
43
  caches.each do |cache|
data/rails/init.rb CHANGED
@@ -1,10 +1,8 @@
1
- begin
2
- require 'memcache'
3
- rescue LoadError
4
- end
5
-
6
1
  require File.expand_path('../../lib/background_cache.rb', __FILE__)
7
2
 
8
3
  ActionController::Base.send(:include, BackgroundCache::Controller)
9
4
  ActionView::Helpers::CacheHelper.send(:include, BackgroundCache::Helper)
10
- ::MemCache.send(:include, BackgroundCache::Memcache) if defined?(::MemCache)
5
+
6
+ ::Dalli::Client.send(:include, BackgroundCache::Memcache) if defined?(::Dalli::Client)
7
+ ::MemCache.send(:include, BackgroundCache::Memcache) if defined?(::MemCache)
8
+ ::Memcached::Rails.send(:include, BackgroundCache::Memcache) if defined?(::Memcached::Rails)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: background_cache
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 4
10
- version: 0.1.4
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Winton Welsh
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-20 00:00:00 Z
18
+ date: 2011-10-24 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rack-test
@@ -64,6 +64,38 @@ dependencies:
64
64
  version: "1.0"
65
65
  type: :development
66
66
  version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: redis
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 2
78
+ - 2
79
+ - 2
80
+ version: 2.2.2
81
+ type: :runtime
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: yajl-ruby
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ~>
90
+ - !ruby/object:Gem::Version
91
+ hash: 23
92
+ segments:
93
+ - 1
94
+ - 0
95
+ - 0
96
+ version: 1.0.0
97
+ type: :runtime
98
+ version_requirements: *id005
67
99
  description: Bust caches before your users do.
68
100
  email:
69
101
  - mail@wintoni.us
@@ -83,8 +115,10 @@ files:
83
115
  - bin/background_cache
84
116
  - init.rb
85
117
  - lib/background_cache.rb
118
+ - lib/background_cache/client.rb
86
119
  - lib/background_cache/config.rb
87
120
  - lib/background_cache/controller.rb
121
+ - lib/background_cache/daemon.rb
88
122
  - lib/background_cache/helper.rb
89
123
  - lib/background_cache/mem_cache.rb
90
124
  - rails/init.rb