robinhood 0.0.1.pre

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ rbx
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ - rbx-19mode
5
+ - jruby-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in robinhood.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Josep Jaume
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Robinhood
2
+
3
+ Robinhood is a DSL for constructing iteration-based synchronous processes
4
+ (aka can't be run as jobs) in a distributed manner.
5
+
6
+ It leverages celluloid actors for each process and uses Redis as a locking
7
+ mechanism to ensure the process is run in a single server.
8
+
9
+ ## Usage
10
+
11
+ ```ruby
12
+ Robinhood.setup do
13
+ process :assigner, timeout: 10.minutes do
14
+ UserAssigner.process!
15
+ end
16
+
17
+ process :sweeper, throttle: 1.minute do
18
+ Sweeper.sweep!
19
+ end
20
+ end
21
+ ```
22
+
23
+ ## How does it work?
24
+
25
+ Each time a process finishes its execution, the lock is released so any other
26
+ server (or system process) can execute it again. This ensures it will be
27
+ executed in a synchronous manner (one after the other).
28
+
29
+ You can also set a timeout (in case a process hangs for some reason) and a
30
+ throttling mechanism (so a process can't be re-scheduled before this time has
31
+ passed).
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,46 @@
1
+ require 'celluloid'
2
+ require 'redis-mutex'
3
+ require 'benchmark'
4
+
5
+ module Robinhood
6
+ class Process
7
+ attr_reader :name, :options
8
+
9
+ include Celluloid
10
+ include Celluloid::Logger
11
+
12
+ def initialize(name, options, block)
13
+ @name = name
14
+ @options = options
15
+ @block = block
16
+ async.run
17
+ end
18
+
19
+ def run
20
+ mutex.lock
21
+
22
+ time = Benchmark.realtime{ @block.call }
23
+
24
+ sleep(difference) if difference = throttle - time
25
+ ensure
26
+ mutex.unlock
27
+ async.run
28
+ end
29
+
30
+ def lock_name
31
+ "robinhood:#{name}:lock"
32
+ end
33
+
34
+ def throttle
35
+ if (throttle = options[:throttle]) != nil
36
+ throttle
37
+ else
38
+ 0.1
39
+ end
40
+ end
41
+
42
+ def mutex
43
+ @mutex ||= Redis::Mutex.new(lock_name, block: 1, sleep: 0.1, expire: 300)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,54 @@
1
+ require "robinhood/process"
2
+ require "celluloid"
3
+
4
+ module Robinhood
5
+ class Setup
6
+ attr_reader :options
7
+
8
+ def initialize(options = {})
9
+ @options = options
10
+ @processes = []
11
+ end
12
+
13
+ def process(name, options = {}, &block)
14
+ @processes << [name, options, block]
15
+ end
16
+
17
+ def redis
18
+ @redis = yield
19
+ end
20
+
21
+ def supervision_group
22
+ @supervision_group ||= Class.new(Celluloid::SupervisionGroup)
23
+ end
24
+
25
+ def start
26
+ setup_supervision_group
27
+ Redis::Classy.db = @redis || Redis.new
28
+
29
+ @supervision_group_actor = if options[:background]
30
+ supervision_group.run!
31
+ else
32
+ supervision_group.run
33
+ end
34
+ end
35
+
36
+ def stop
37
+ @supervision_group_actor.finalize if @supervision_group_actor
38
+ end
39
+
40
+ def redis_options
41
+ options[:redis] || {}
42
+ end
43
+
44
+ def setup_supervision_group
45
+ @processes.each do |process|
46
+ name, options, block = process
47
+
48
+ supervision_group.supervise Process,
49
+ as: "robinhood_#{name}",
50
+ args: [name, options.merge(autostart: true), block]
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,3 @@
1
+ module Robinhood
2
+ VERSION = "0.0.1.pre"
3
+ end
data/lib/robinhood.rb ADDED
@@ -0,0 +1,20 @@
1
+ require "robinhood/version"
2
+ require "robinhood/setup"
3
+ require "celluloid/autostart"
4
+
5
+ module Robinhood
6
+ def self.setup(options = {}, &block)
7
+ @setup ||= Setup.new(options)
8
+ @setup.instance_eval(&block)
9
+ @setup.start
10
+ end
11
+
12
+ def self.stop
13
+ @setup.stop if @setup
14
+ end
15
+
16
+ def self.reset!
17
+ stop
18
+ @setup = nil
19
+ end
20
+ end
data/robinhood.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'robinhood/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "robinhood"
8
+ spec.version = Robinhood::VERSION
9
+ spec.authors = ["Josep Jaume"]
10
+ spec.email = ["josepjaume@gmail.com"]
11
+ spec.description = %q{Robin hood leverages celluloid actors and redis-mutex to distribute long-lived, single-instance processes across multiple servers.}
12
+ spec.summary = spec.description
13
+ spec.homepage = "http://www.codegram.com"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'celluloid'
22
+ spec.add_dependency 'redis-mutex'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "pry"
28
+ spec.add_development_dependency "pry-nav"
29
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+ require "robinhood"
3
+
4
+ module Robinhood
5
+ describe ".setup" do
6
+ it "creates actors for each process" do
7
+ Robinhood.setup(background: true) do
8
+ process(:ed){}
9
+ process(:balls){}
10
+ end
11
+
12
+ sleep(1)
13
+
14
+ expect(Celluloid::Actor[:robinhood_ed]).to_not be_nil
15
+ expect(Celluloid::Actor[:robinhood_balls]).to_not be_nil
16
+ end
17
+
18
+ it "executes a process iteratively until it ends" do
19
+ queue = [1, 2]
20
+
21
+ Robinhood.setup(background: true) do
22
+ process :test do
23
+ queue.pop
24
+ end
25
+ end
26
+
27
+ sleep(1)
28
+ expect(queue).to be_empty
29
+ end
30
+
31
+ it "allows setting an arbitrary throttle" do
32
+ queue = [1, 2]
33
+
34
+ Robinhood.setup(background: true) do
35
+ process :test, throttle: 0.5 do
36
+ queue.pop
37
+ end
38
+ end
39
+
40
+ sleep(0.2)
41
+ expect(queue).not_to be_empty
42
+ sleep(1)
43
+ expect(queue).to be_empty
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ require "pry"
2
+ require "pry-nav"
3
+
4
+ RSpec.configure do |config|
5
+ config.color = true
6
+
7
+ unless ENV["TRAVIS"]
8
+ config.formatter = :documentation
9
+ end
10
+
11
+ config.before(:each) do
12
+ Celluloid.logger = nil
13
+ redis = Redis.new
14
+ redis.flushdb
15
+ end
16
+
17
+ config.after(:each) do
18
+ Robinhood.reset!
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,195 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: robinhood
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: 6
5
+ version: 0.0.1.pre
6
+ platform: ruby
7
+ authors:
8
+ - Josep Jaume
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ none: false
21
+ requirement: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ! '>='
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ none: false
27
+ name: celluloid
28
+ type: :runtime
29
+ prerelease: false
30
+ - !ruby/object:Gem::Dependency
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ none: false
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ none: false
43
+ name: redis-mutex
44
+ type: :runtime
45
+ prerelease: false
46
+ - !ruby/object:Gem::Dependency
47
+ version_requirements: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ~>
50
+ - !ruby/object:Gem::Version
51
+ version: '1.3'
52
+ none: false
53
+ requirement: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: '1.3'
58
+ none: false
59
+ name: bundler
60
+ type: :development
61
+ prerelease: false
62
+ - !ruby/object:Gem::Dependency
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ none: false
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ none: false
75
+ name: rake
76
+ type: :development
77
+ prerelease: false
78
+ - !ruby/object:Gem::Dependency
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ none: false
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ none: false
91
+ name: rspec
92
+ type: :development
93
+ prerelease: false
94
+ - !ruby/object:Gem::Dependency
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ none: false
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ! '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ none: false
107
+ name: pry
108
+ type: :development
109
+ prerelease: false
110
+ - !ruby/object:Gem::Dependency
111
+ version_requirements: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ none: false
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ none: false
123
+ name: pry-nav
124
+ type: :development
125
+ prerelease: false
126
+ description: Robin hood leverages celluloid actors and redis-mutex to distribute long-lived,
127
+ single-instance processes across multiple servers.
128
+ email:
129
+ - josepjaume@gmail.com
130
+ executables: []
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - !binary |-
135
+ LmdpdGlnbm9yZQ==
136
+ - !binary |-
137
+ LnJ1YnktdmVyc2lvbg==
138
+ - !binary |-
139
+ LnRyYXZpcy55bWw=
140
+ - !binary |-
141
+ R2VtZmlsZQ==
142
+ - !binary |-
143
+ TElDRU5TRS50eHQ=
144
+ - !binary |-
145
+ UkVBRE1FLm1k
146
+ - !binary |-
147
+ UmFrZWZpbGU=
148
+ - !binary |-
149
+ bGliL3JvYmluaG9vZC5yYg==
150
+ - !binary |-
151
+ bGliL3JvYmluaG9vZC9wcm9jZXNzLnJi
152
+ - !binary |-
153
+ bGliL3JvYmluaG9vZC9zZXR1cC5yYg==
154
+ - !binary |-
155
+ bGliL3JvYmluaG9vZC92ZXJzaW9uLnJi
156
+ - !binary |-
157
+ cm9iaW5ob29kLmdlbXNwZWM=
158
+ - !binary |-
159
+ c3BlYy9hY2NlcHRhbmNlL3NldHVwX3NwZWMucmI=
160
+ - !binary |-
161
+ c3BlYy9zcGVjX2hlbHBlci5yYg==
162
+ homepage: http://www.codegram.com
163
+ licenses:
164
+ - MIT
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ hash: 2002549777813010636
174
+ segments:
175
+ - 0
176
+ version: '0'
177
+ none: false
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ! '>'
181
+ - !ruby/object:Gem::Version
182
+ version: 1.3.1
183
+ none: false
184
+ requirements: []
185
+ rubyforge_project:
186
+ rubygems_version: 1.8.25
187
+ signing_key:
188
+ specification_version: 3
189
+ summary: Robin hood leverages celluloid actors and redis-mutex to distribute long-lived,
190
+ single-instance processes across multiple servers.
191
+ test_files:
192
+ - !binary |-
193
+ c3BlYy9hY2NlcHRhbmNlL3NldHVwX3NwZWMucmI=
194
+ - !binary |-
195
+ c3BlYy9zcGVjX2hlbHBlci5yYg==