resque-state 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 31009a841c78f3ee6288076f7aaf5e5bb7e1f1b0
4
+ data.tar.gz: 7afc133998ecc29bb2cc87e35b3af102a1d9cc14
5
+ SHA512:
6
+ metadata.gz: 55a8fe604e4f315a3c994f5381fe35c824a0d8995c99f9c573afa7a882d4ff719df3a157e8d923f5b9a1210162264b590f0d67537e6771d4fedcf5ee355f02a2
7
+ data.tar.gz: d7d756b11b3dbd8cde9f6c3694a6f094c72a772412c75c400fce68ef658859a97e507c01701047f84682d6c23e93d245241a0ecfaa8a0210027d28241e01dbe9
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
4
+ - jruby
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'resque', '~>1.19'
4
+
5
+ group :test do
6
+ gem 'mocha', '~>0.9'
7
+ gem 'minitest', '~> 5.5'
8
+ gem 'simplecov'
9
+ gem 'fakeredis', '~> 0.5.0'
10
+ gem "codeclimate-test-reporter", require: nil
11
+ end
12
+
13
+ group :development do
14
+ gem 'jeweler', '~> 2.1'
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,102 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.4.0)
5
+ builder (3.2.2)
6
+ codeclimate-test-reporter (0.6.0)
7
+ simplecov (>= 0.7.1, < 1.0.0)
8
+ descendants_tracker (0.0.4)
9
+ thread_safe (~> 0.3, >= 0.3.1)
10
+ docile (1.1.5)
11
+ fakeredis (0.5.0)
12
+ redis (~> 3.0)
13
+ faraday (0.9.2)
14
+ multipart-post (>= 1.2, < 3)
15
+ git (1.3.0)
16
+ github_api (0.14.5)
17
+ addressable (~> 2.4.0)
18
+ descendants_tracker (~> 0.0.4)
19
+ faraday (~> 0.8, < 0.10)
20
+ hashie (>= 3.4)
21
+ oauth2 (~> 1.0)
22
+ hashie (3.4.4)
23
+ highline (1.7.8)
24
+ jeweler (2.1.1)
25
+ builder
26
+ bundler (>= 1.0)
27
+ git (>= 1.2.5)
28
+ github_api
29
+ highline (>= 1.6.15)
30
+ nokogiri (>= 1.5.10)
31
+ rake
32
+ rdoc
33
+ semver
34
+ json (1.8.3)
35
+ json (1.8.3-java)
36
+ jwt (1.5.4)
37
+ metaclass (0.0.4)
38
+ mini_portile2 (2.1.0)
39
+ minitest (5.9.0)
40
+ mocha (0.14.0)
41
+ metaclass (~> 0.0.1)
42
+ mono_logger (1.1.0)
43
+ multi_json (1.12.1)
44
+ multi_xml (0.5.5)
45
+ multipart-post (2.0.0)
46
+ nokogiri (1.6.8)
47
+ mini_portile2 (~> 2.1.0)
48
+ pkg-config (~> 1.1.7)
49
+ nokogiri (1.6.8-java)
50
+ oauth2 (1.2.0)
51
+ faraday (>= 0.8, < 0.10)
52
+ jwt (~> 1.0)
53
+ multi_json (~> 1.3)
54
+ multi_xml (~> 0.5)
55
+ rack (>= 1.2, < 3)
56
+ pkg-config (1.1.7)
57
+ rack (1.6.4)
58
+ rack-protection (1.5.3)
59
+ rack
60
+ rake (11.2.2)
61
+ rdoc (4.2.2)
62
+ json (~> 1.4)
63
+ redis (3.3.1)
64
+ redis-namespace (1.5.2)
65
+ redis (~> 3.0, >= 3.0.4)
66
+ resque (1.26.0)
67
+ mono_logger (~> 1.0)
68
+ multi_json (~> 1.0)
69
+ redis-namespace (~> 1.3)
70
+ sinatra (>= 0.9.2)
71
+ vegas (~> 0.1.2)
72
+ semver (1.0.1)
73
+ simplecov (0.12.0)
74
+ docile (~> 1.1.0)
75
+ json (>= 1.8, < 3)
76
+ simplecov-html (~> 0.10.0)
77
+ simplecov-html (0.10.0)
78
+ sinatra (1.4.7)
79
+ rack (~> 1.5)
80
+ rack-protection (~> 1.4)
81
+ tilt (>= 1.3, < 3)
82
+ thread_safe (0.3.5)
83
+ thread_safe (0.3.5-java)
84
+ tilt (2.0.5)
85
+ vegas (0.1.11)
86
+ rack (>= 1.0.0)
87
+
88
+ PLATFORMS
89
+ java
90
+ ruby
91
+
92
+ DEPENDENCIES
93
+ codeclimate-test-reporter
94
+ fakeredis (~> 0.5.0)
95
+ jeweler (~> 2.1)
96
+ minitest (~> 5.5)
97
+ mocha (~> 0.9)
98
+ resque (~> 1.19)
99
+ simplecov
100
+
101
+ BUNDLED WITH
102
+ 1.12.5
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2016 Nathan V
2
+ Copyright (c) 2009 Aaron Quint
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,208 @@
1
+ = resque-state
2
+
3
+ {<img src="https://img.shields.io/badge/license-MIT-blue.svg" />}[https://github.com/nathan-v/resque-state/blob/master/LICENSE]
4
+
5
+ {<img src="https://codeclimate.com/github/nathan-v/resque-state/badges/gpa.svg" />}[https://codeclimate.com/github/nathan-v/resque-state]
6
+ {<img src="https://codeclimate.com/github/nathan-v/resque-state/badges/issue_count.svg" />}[https://codeclimate.com/github/nathan-v/resque-state]
7
+ {<img src="https://codeclimate.com/github/nathan-v/resque-state/badges/coverage.svg" />}[https://codeclimate.com/github/nathan-v/resque-state/coverage]
8
+ {<img src="https://travis-ci.org/nathan-v/resque-state.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/nathan-v/resque-state]
9
+ {<img src="https://gemnasium.com/badges/github.com/nathan-v/resque-state.svg" />}[https://gemnasium.com/github.com/nathan-v/resque-state]
10
+ {<img src="https://img.shields.io/github/issues/nathan-v/resque-state.svg" />}[https://github.com/nathan-v/resque-state/issues]
11
+
12
+
13
+ resque-state is an extension to the resque queue system that provides simple trackable jobs.
14
+
15
+ == About
16
+
17
+ resque-state provides a set of simple classes that extend resque's default
18
+ functionality (with 0% monkey patching) to give apps a way to track specific
19
+ job instances and their state. It achieves this by giving job instances UUID's
20
+ and allowing the job instances to report their state from within their iterations.
21
+
22
+ == Installation
23
+
24
+ Ruby 1.9.3 and up are supported.
25
+
26
+ resque-state <b>requires Redis >= 1.1</b> (though I recommend getting the latest stable version).
27
+ You can download Redis here: http://redis.io/ or install it
28
+ using homebrew (brew install redis).
29
+
30
+ Install the resque-state gem (which will pull in the dependencies).
31
+
32
+ gem install resque-state
33
+
34
+ With newer Rails add this to your Gemfile:
35
+
36
+ # Gemfile
37
+ gem 'resque-state'
38
+
39
+ Then in an initializer:
40
+
41
+ # config/initializers/resque.rb
42
+ Resque.redis = "your/redis/socket" # default localhost:6379
43
+ Resque::Plugins::State::Hash.expire_in = (24 * 60 * 60) # 24hrs in seconds
44
+
45
+ == Usage
46
+
47
+ The most direct way to use resque-state is to create your jobs using the
48
+ Resque::Plugins::State module. An example job would look something like:
49
+
50
+ class SleepJob
51
+ include Resque::Plugins::State
52
+
53
+ def perform
54
+ total = (options['length'] || 1000).to_i
55
+ total.times do |i|
56
+ num = i+1
57
+ at(num, total, "At #{num} of #{total}")
58
+ sleep(1)
59
+ end
60
+ end
61
+ end
62
+
63
+ One major difference is that instead of implementing <tt>perform</tt> as a
64
+ class method, we do our job implementation within instances of the job class.
65
+
66
+ In order to queue a SleepJob up, we also won't use <tt>Resque.enqueue</tt>, instead
67
+ we'll use the <tt>create</tt> class method which will wrap <tt>enqueue</tt> and
68
+ creating a unique id (UUID) for us to track the job with.
69
+
70
+ job_id = SleepJob.create(length: 100)
71
+
72
+ This will create a UUID enqueue the job and pass the :length option on the SleepJob
73
+ instance as options['length'] (as you can see above).
74
+
75
+ Now that we have a UUID its really easy to get the state:
76
+
77
+ state = Resque::Plugins::State::Hash.get(job_id)
78
+
79
+ This returns a Resque::Plugins::State::Hash object, which is a Hash (with benefits).
80
+
81
+ state.pct_complete #=> 0
82
+ state.status #=> 'queued'
83
+ state.queued? #=> true
84
+ state.working? #=> false
85
+ state.time #=> Time object
86
+ state.message #=> "Created at ..."
87
+
88
+ Once the worker reserves the job, the instance of SleepJob updates the state at
89
+ each iteration using <tt>at()</tt>
90
+
91
+ state = Resque::Plugins::State::Hash.get(job_id)
92
+ state.working? #=> true
93
+ state.num #=> 5
94
+ state.total #=> 100
95
+ state.pct_complete #=> 5
96
+
97
+ If an error occurs within the job instance, the state is set to 'failed' and then
98
+ the error is re-raised so that Resque can capture it.
99
+
100
+ Its also possible to get a list of current/recent job statuses:
101
+
102
+ Resque::Plugins::State::Hash.statuses #=> [#<Resque::Plugins::State::Hash>, ...]
103
+
104
+ === Passing back data from the job
105
+
106
+ You may want to save data from inside the job to access it from outside the job.
107
+
108
+ A common use-case is web-triggered jobs that create files, later available for
109
+ download by the user.
110
+
111
+ A Status is actually just a hash, so inside a job you can do:
112
+
113
+ set_status(filename: "myfilename")
114
+
115
+ Also, all the status setting methods take any number of hash arguments. So you could do:
116
+
117
+ completed('filename' => '/myfilename')
118
+
119
+ === Kill! Kill! Kill!
120
+
121
+ Because we're tracking UUIDs per instance, and we're checking in/updating the status
122
+ on each iteration (using <tt>at</tt> or <tt>tick</tt>) we can kill specific jobs
123
+ by UUID.
124
+
125
+ Resque::Plugins::State::Hash.kill(job_id)
126
+
127
+ The next time the job at job_id calls <tt>at</tt> or <tt>tick</tt>, it will raise a <tt>Killed</tt>
128
+ error and set the status to killed.
129
+
130
+ === Hold up: Pausing
131
+
132
+ Since we perhaps might want to just have a job sit and wait a bit rather than have it die
133
+ completely there's pause. This tells the job to sleep for 10 seconds before checking in
134
+ again.
135
+
136
+ Resque::Plugins::State::Hash.pause(job_id)
137
+
138
+ The next time the job at job_id calls <tt>at</tt> or <tt>tick</tt>, it will start a while
139
+ loop with a 10 second sleep until Resque::Plugins::State::Hash.unpause is called.
140
+
141
+ === Percent Complete and setting the message
142
+
143
+ Use <tt>at</tt> or <tt>tick</tt> to show progress in your job's <tt>perform</tt> function
144
+ (which is displayed on the resque-web state tab). This will also be where <tt>Killed</tt>
145
+ is raised if the job is killed.
146
+
147
+ at(steps_completed, total_steps, "${steps_completed} of #{total_steps} steps completed!")
148
+
149
+ === Expiration
150
+
151
+ Since Redis is RAM based, we probably don't want to keep these statuses around forever
152
+ (at least until @antirez releases the VM feature). By setting expire_in, all statuses
153
+ and their related keys will expire in expire_in seconds from the last time theyre updated:
154
+
155
+ Resque::Plugins::State::Hash.expire_in = (60 * 60) # 1 hour
156
+
157
+ === Testing
158
+
159
+ Recent versions of Resque introduced <tt>Resque.inline</tt> which changes the behavior to
160
+ instead of enqueueing and performing jobs to just executing them inline. In Resque
161
+ itself this removes the dependency on a Redis, however, <tt>Resque::State</tt> uses Redis
162
+ to store information about jobs, so though <tt>inline</tt> "works", you will still need
163
+ to use or mock a redis connection. You should be able to use a library like
164
+ https://github.com/causes/mock_redis alongside <tt>inline</tt> if you really want to
165
+ avoid Redis connections in your test.
166
+
167
+ === resque-web
168
+
169
+ Though the main purpose of these trackable jobs is to allow you to surface the status
170
+ of user created jobs through your apps' own UI, I've added a simple example UI
171
+ as a plugin to resque-web. This adds a State tab to resque-web
172
+
173
+ To use, you need to setup a resque-web config file:
174
+
175
+ # ~/resque_conf.rb
176
+ require 'resque/state_server'
177
+
178
+ Then start resque-web with your config:
179
+
180
+ resque-web ~/resque_conf.rb
181
+
182
+ If you're using Rails you can just require 'resque/state_server' in your resque
183
+ initializer or application.rb.
184
+
185
+
186
+ == More
187
+
188
+ * Source: http://github.com/nathan-v/resque-state
189
+ * API Docs: http://rdoc.info/projects/nathan-v/resque-state
190
+ * Examples: http://github.com/nathan-v/resque-state/tree/master/examples
191
+ * Resque: https://github.com/resque/resque
192
+
193
+ == Thanks
194
+
195
+ Resque is awesome, @defunkt needs a shout-out.
196
+
197
+ == Note on Patches/Pull Requests
198
+
199
+ PRs are welcome. Please always include relevant tests and ensure your changes follow
200
+ Ruby style conventions as much as possible.
201
+
202
+ == Copyright
203
+
204
+ Copyright (c) 2016 Nathan V.
205
+
206
+ Copyright (c) 2010 Aaron Quint.
207
+
208
+ MIT licensed. See LICENSE file for details.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ $LOAD_PATH.unshift './lib'
2
+
3
+ require 'rake'
4
+ require 'resque-state'
5
+ require 'resque/tasks'
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = 'resque-state'
11
+ gem.version = Resque::Plugins::State::VERSION.dup
12
+ gem.summary = %(resque-state is an extension to the resque queue system
13
+ that provides simple trackable jobs.).gsub("\n", ' ').squeeze(' ')
14
+ gem.description = %(resque-state is an extension to the resque queue
15
+ system that provides simple trackable jobs. It provides a
16
+ Resque::Plugins::State::Hash class which can set/get the statuses of jobs
17
+ and a Resque::Plugins::State class that, when included, provides easily
18
+ trackable/killable/pausable jobs.).gsub("\n", ' ').squeeze(' ')
19
+ gem.email = 'nathan.v@gmail.com'
20
+ gem.homepage = 'http://github.com/nathan-v/resque-state'
21
+ gem.rubyforge_project = 'nathan-v'
22
+ gem.authors = ['Aaron Quint', 'Nathan V']
23
+ gem.licenses = 'MIT'
24
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20
25
+ # for additional settings
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+ rescue LoadError
29
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install'\
30
+ ' jeweler'.gsub("\n", ' ').squeeze(' ')
31
+ end
32
+
33
+ require 'rake/testtask'
34
+ Rake::TestTask.new(:test) do |test|
35
+ test.libs << 'lib' << 'test'
36
+ test.pattern = 'test/**/test_*.rb'
37
+ test.verbose = true
38
+ end
39
+
40
+ desc 'Generates a coverage report'
41
+ task :coverage do
42
+ ENV['COVERAGE'] = 'true'
43
+ Rake::Task['test'].execute
44
+ end
45
+
46
+ task :test
47
+
48
+ task default: :coverage
@@ -0,0 +1,36 @@
1
+ require 'resque/job_with_state' # in rails you would probably do this in an initializer
2
+
3
+ # sleeps for _length_ seconds updating the status every second
4
+
5
+ class SleepJob
6
+ include Resque::Plugins::State
7
+
8
+ def perform
9
+ total = options.has_key?('length') ? options['length'].to_i : 1000
10
+ num = 0
11
+ while num < total
12
+ at(num, total, "At #{num} of #{total}")
13
+ sleep(1)
14
+ num += 1
15
+ end
16
+ completed
17
+ end
18
+
19
+ end
20
+
21
+
22
+ if __FILE__ == $0
23
+ # Make sure you have a worker running
24
+ # rake -rexamples/sleep_job.rb resque:work QUEUE=statused
25
+
26
+ # running the job
27
+ puts "Creating the SleepJob"
28
+ job_id = SleepJob.create :length => 100
29
+ puts "Got back #{job_id}"
30
+
31
+ # check the status until its complete
32
+ while status = Resque::Plugins::State::Hash.get(job_id) and !status.completed? && !status.failed?
33
+ sleep 1
34
+ puts status.inspect
35
+ end
36
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'resque-state'
@@ -0,0 +1,5 @@
1
+ module Resque
2
+ class JobWithState
3
+ include Resque::Plugins::State
4
+ end
5
+ end