resque-status 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{resque-status}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aaron Quint"]
12
+ s.date = %q{2010-01-19}
13
+ s.description = %q{resque-status is an extension to the resque queue system that provides simple trackable jobs. It provides a Resque::Status class which can set/get the statuses of jobs and a Resque::JobWithStatus class that when subclassed provides easily trackable/killable jobs.}
14
+ s.email = %q{aaron@quirkey.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "examples/sleep_job.rb",
26
+ "init.rb",
27
+ "lib/resque/job_with_status.rb",
28
+ "lib/resque/server/views/status.erb",
29
+ "lib/resque/server/views/status_styles.erb",
30
+ "lib/resque/server/views/statuses.erb",
31
+ "lib/resque/status.rb",
32
+ "lib/resque/status_server.rb",
33
+ "resque-status.gemspec",
34
+ "test/redis-test.conf",
35
+ "test/test_helper.rb",
36
+ "test/test_resque-job_with_status.rb",
37
+ "test/test_resque-status.rb"
38
+ ]
39
+ s.homepage = %q{http://github.com/quirkey/resque-status}
40
+ s.rdoc_options = ["--charset=UTF-8"]
41
+ s.require_paths = ["lib"]
42
+ s.rubyforge_project = %q{quirkey}
43
+ s.rubygems_version = %q{1.3.5}
44
+ s.summary = %q{resque-status is an extension to the resque queue system that provides simple trackable jobs.}
45
+ s.test_files = [
46
+ "test/test_helper.rb",
47
+ "test/test_resque-job_with_status.rb",
48
+ "test/test_resque-status.rb",
49
+ "examples/sleep_job.rb"
50
+ ]
51
+
52
+ if s.respond_to? :specification_version then
53
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
54
+ s.specification_version = 3
55
+
56
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
57
+ s.add_runtime_dependency(%q<uuid>, [">= 2.0.2"])
58
+ s.add_runtime_dependency(%q<resque>, [">= 1.3.1"])
59
+ s.add_runtime_dependency(%q<redisk>, [">= 0.2.0"])
60
+ s.add_development_dependency(%q<shoulda>, [">= 2.10.2"])
61
+ else
62
+ s.add_dependency(%q<uuid>, [">= 2.0.2"])
63
+ s.add_dependency(%q<resque>, [">= 1.3.1"])
64
+ s.add_dependency(%q<redisk>, [">= 0.2.0"])
65
+ s.add_dependency(%q<shoulda>, [">= 2.10.2"])
66
+ end
67
+ else
68
+ s.add_dependency(%q<uuid>, [">= 2.0.2"])
69
+ s.add_dependency(%q<resque>, [">= 1.3.1"])
70
+ s.add_dependency(%q<redisk>, [">= 0.2.0"])
71
+ s.add_dependency(%q<shoulda>, [">= 2.10.2"])
72
+ end
73
+ end
74
+
@@ -0,0 +1,132 @@
1
+ # Redis configuration file example
2
+
3
+ # By default Redis does not run as a daemon. Use 'yes' if you need it.
4
+ # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
5
+ daemonize yes
6
+
7
+ # When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
8
+ # You can specify a custom pid file location here.
9
+ pidfile ./test/redis-test.pid
10
+
11
+ # Accept connections on the specified port, default is 6379
12
+ port 9736
13
+
14
+ # If you want you can bind a single interface, if the bind option is not
15
+ # specified all the interfaces will listen for connections.
16
+ #
17
+ # bind 127.0.0.1
18
+
19
+ # Close the connection after a client is idle for N seconds (0 to disable)
20
+ timeout 300
21
+
22
+ # Save the DB on disk:
23
+ #
24
+ # save <seconds> <changes>
25
+ #
26
+ # Will save the DB if both the given number of seconds and the given
27
+ # number of write operations against the DB occurred.
28
+ #
29
+ # In the example below the behaviour will be to save:
30
+ # after 900 sec (15 min) if at least 1 key changed
31
+ # after 300 sec (5 min) if at least 10 keys changed
32
+ # after 60 sec if at least 10000 keys changed
33
+ save 900 1
34
+ save 300 10
35
+ save 60 10000
36
+
37
+ # The filename where to dump the DB
38
+ dbfilename dump.rdb
39
+
40
+ # For default save/load DB in/from the working directory
41
+ # Note that you must specify a directory not a file name.
42
+ dir ./test/
43
+
44
+ # Set server verbosity to 'debug'
45
+ # it can be one of:
46
+ # debug (a lot of information, useful for development/testing)
47
+ # notice (moderately verbose, what you want in production probably)
48
+ # warning (only very important / critical messages are logged)
49
+ loglevel debug
50
+
51
+ # Specify the log file name. Also 'stdout' can be used to force
52
+ # the demon to log on the standard output. Note that if you use standard
53
+ # output for logging but daemonize, logs will be sent to /dev/null
54
+ logfile stdout
55
+
56
+ # Set the number of databases. The default database is DB 0, you can select
57
+ # a different one on a per-connection basis using SELECT <dbid> where
58
+ # dbid is a number between 0 and 'databases'-1
59
+ databases 16
60
+
61
+ ################################# REPLICATION #################################
62
+
63
+ # Master-Slave replication. Use slaveof to make a Redis instance a copy of
64
+ # another Redis server. Note that the configuration is local to the slave
65
+ # so for example it is possible to configure the slave to save the DB with a
66
+ # different interval, or to listen to another port, and so on.
67
+
68
+ # slaveof <masterip> <masterport>
69
+
70
+ ################################## SECURITY ###################################
71
+
72
+ # Require clients to issue AUTH <PASSWORD> before processing any other
73
+ # commands. This might be useful in environments in which you do not trust
74
+ # others with access to the host running redis-server.
75
+ #
76
+ # This should stay commented out for backward compatibility and because most
77
+ # people do not need auth (e.g. they run their own servers).
78
+
79
+ # requirepass foobared
80
+
81
+ ################################### LIMITS ####################################
82
+
83
+ # Set the max number of connected clients at the same time. By default there
84
+ # is no limit, and it's up to the number of file descriptors the Redis process
85
+ # is able to open. The special value '0' means no limts.
86
+ # Once the limit is reached Redis will close all the new connections sending
87
+ # an error 'max number of clients reached'.
88
+
89
+ # maxclients 128
90
+
91
+ # Don't use more memory than the specified amount of bytes.
92
+ # When the memory limit is reached Redis will try to remove keys with an
93
+ # EXPIRE set. It will try to start freeing keys that are going to expire
94
+ # in little time and preserve keys with a longer time to live.
95
+ # Redis will also try to remove objects from free lists if possible.
96
+ #
97
+ # If all this fails, Redis will start to reply with errors to commands
98
+ # that will use more memory, like SET, LPUSH, and so on, and will continue
99
+ # to reply to most read-only commands like GET.
100
+ #
101
+ # WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
102
+ # 'state' server or cache, not as a real DB. When Redis is used as a real
103
+ # database the memory usage will grow over the weeks, it will be obvious if
104
+ # it is going to use too much memory in the long run, and you'll have the time
105
+ # to upgrade. With maxmemory after the limit is reached you'll start to get
106
+ # errors for write operations, and this may even lead to DB inconsistency.
107
+
108
+ # maxmemory <bytes>
109
+
110
+ ############################### ADVANCED CONFIG ###############################
111
+
112
+ # Glue small output buffers together in order to send small replies in a
113
+ # single TCP packet. Uses a bit more CPU but most of the times it is a win
114
+ # in terms of number of queries per second. Use 'yes' if unsure.
115
+ glueoutputbuf yes
116
+
117
+ # Use object sharing. Can save a lot of memory if you have many common
118
+ # string in your dataset, but performs lookups against the shared objects
119
+ # pool so it uses more CPU and can be a bit slower. Usually it's a good
120
+ # idea.
121
+ #
122
+ # When object sharing is enabled (shareobjects yes) you can use
123
+ # shareobjectspoolsize to control the size of the pool used in order to try
124
+ # object sharing. A bigger pool size will lead to better sharing capabilities.
125
+ # In general you want this value to be at least the double of the number of
126
+ # very common strings you have in your dataset.
127
+ #
128
+ # WARNING: object sharing is experimental, don't enable this feature
129
+ # in production before of Redis 1.0-stable. Still please try this feature in
130
+ # your development environment so that we can test it better.
131
+ shareobjects no
132
+ shareobjectspoolsize 1024
@@ -0,0 +1,82 @@
1
+ dir = File.dirname(File.expand_path(__FILE__))
2
+ $LOAD_PATH.unshift dir + '/../lib'
3
+ $TESTING = true
4
+ require 'test/unit'
5
+ require 'rubygems'
6
+ require 'shoulda'
7
+ require 'mocha'
8
+
9
+ require 'resque/status'
10
+ require 'resque/job_with_status'
11
+
12
+ class Test::Unit::TestCase
13
+ end
14
+
15
+ #
16
+ # make sure we can run redis
17
+ #
18
+
19
+ if !system("which redis-server")
20
+ puts '', "** can't find `redis-server` in your path"
21
+ puts "** try running `sudo rake install`"
22
+ abort ''
23
+ end
24
+
25
+ #
26
+ # start our own redis when the tests start,
27
+ # kill it when they end
28
+ #
29
+
30
+ at_exit do
31
+ next if $!
32
+
33
+ if defined?(MiniTest)
34
+ exit_code = MiniTest::Unit.new.run(ARGV)
35
+ else
36
+ exit_code = Test::Unit::AutoRunner.run
37
+ end
38
+
39
+ pid = `ps -e -o pid,command | grep [r]edis-test`.split(" ")[0]
40
+ puts "Killing test redis server..."
41
+ `rm -f #{dir}/dump.rdb`
42
+ Process.kill("KILL", pid.to_i)
43
+ exit exit_code
44
+ end
45
+
46
+ puts "Starting redis for testing at localhost:9736..."
47
+ `redis-server #{dir}/redis-test.conf`
48
+ Resque.redis = 'localhost:9736'
49
+
50
+
51
+ #### Fixtures
52
+
53
+ class WorkingJob < Resque::JobWithStatus
54
+
55
+ def perform
56
+ total = options['num']
57
+ (1..total).each do |num|
58
+ at(num, total, "At #{num}")
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ class ErrorJob < Resque::JobWithStatus
65
+
66
+ def perform
67
+ raise "I'm a bad little job"
68
+ end
69
+
70
+ end
71
+
72
+ class KillableJob < Resque::JobWithStatus
73
+
74
+ def perform
75
+ Resque.redis.set("#{uuid}:iterations", 0)
76
+ 100.times do |num|
77
+ Resque.redis.incr("#{uuid}:iterations")
78
+ at(num, 100, "At #{num} of 100")
79
+ end
80
+ end
81
+
82
+ end
@@ -0,0 +1,180 @@
1
+ require 'test_helper'
2
+
3
+ class TestResqueJobWithStatus < Test::Unit::TestCase
4
+
5
+ context "Resque::JobWithStatus" do
6
+ setup do
7
+ Resque.redis.flush_all
8
+ end
9
+
10
+ context ".create" do
11
+ setup do
12
+ @uuid = WorkingJob.create('num' => 100)
13
+ end
14
+
15
+ should "add the job to the queue" do
16
+ assert_equal 1, Resque.size(:statused)
17
+ end
18
+
19
+ should "set the queued object to the current class" do
20
+ job = Resque.pop(:statused)
21
+ assert_equal @uuid, job['args'].first
22
+ assert_equal "WorkingJob", job['class']
23
+ end
24
+
25
+ should "add the uuid to the statuses" do
26
+ assert_contains Resque::Status.status_ids, @uuid
27
+ end
28
+
29
+ should "return a UUID" do
30
+ assert_match(/^\w{32}$/, @uuid)
31
+ end
32
+
33
+ end
34
+
35
+ context ".enqueue" do
36
+ setup do
37
+ @uuid = Resque::JobWithStatus.enqueue(WorkingJob, :num => 100)
38
+ @payload = Resque.pop(:statused)
39
+ end
40
+
41
+ should "add the job with the specific class to the queue" do
42
+ assert_equal "WorkingJob", @payload['class']
43
+ end
44
+
45
+ should "add the arguments to the options hash" do
46
+ assert_equal @uuid, @payload['args'].first
47
+ end
48
+
49
+ should "add the uuid to the statuses" do
50
+ assert_contains Resque::Status.status_ids, @uuid
51
+ end
52
+
53
+ should "return UUID" do
54
+ assert_match(/^\w{32}$/, @uuid)
55
+ end
56
+
57
+ end
58
+
59
+ context ".perform" do
60
+ setup do
61
+ @uuid = WorkingJob.create(:num => 100)
62
+ @payload = Resque.pop(:statused)
63
+ @performed = WorkingJob.perform(*@payload['args'])
64
+ end
65
+
66
+ should "load load a new instance of the klass" do
67
+ assert @performed.is_a?(WorkingJob)
68
+ end
69
+
70
+ should "set the uuid" do
71
+ assert_equal @uuid, @performed.uuid
72
+ end
73
+
74
+ should "set the status" do
75
+ assert @performed.status.is_a?(Resque::Status)
76
+ assert_equal 'WorkingJob', @performed.status.name
77
+ end
78
+
79
+ before_should "call perform on the inherited class" do
80
+ WorkingJob.any_instance.expects(:perform).once
81
+ end
82
+
83
+ end
84
+
85
+ context "killing a job" do
86
+ setup do
87
+ @uuid = KillableJob.create(:num => 100)
88
+ @payload = Resque.pop(:statused)
89
+ Resque::Status.kill(@uuid)
90
+ assert_contains Resque::Status.kill_ids, @uuid
91
+ @performed = KillableJob.perform(*@payload['args'])
92
+ @status = Resque::Status.get(@uuid)
93
+ end
94
+
95
+ should "set the status to killed" do
96
+ assert_equal 'killed', @status.status
97
+ assert @status.killed?
98
+ assert !@status.completed?
99
+ end
100
+
101
+ should "only perform iterations up to kill" do
102
+ assert_equal 1, Resque.redis.get("#{@uuid}:iterations").to_i
103
+ end
104
+
105
+ should "not persist the kill key" do
106
+ assert_does_not_contain Resque::Status.kill_ids, @uuid
107
+ end
108
+ end
109
+
110
+ context "with an invoked job" do
111
+ setup do
112
+ @job = WorkingJob.new('123', {'num' => 100})
113
+ end
114
+
115
+ context "#at" do
116
+ setup do
117
+ @job.at(50, 100, "At 50%")
118
+ end
119
+
120
+ should "calculate percent" do
121
+ assert_equal 50, @job.status.pct_complete
122
+ end
123
+
124
+ should "set status" do
125
+ assert_equal 'working', @job.status.status
126
+ end
127
+
128
+ should "save message" do
129
+ assert_equal "At 50%", @job.status.message
130
+ end
131
+ end
132
+
133
+ context "#failed" do
134
+ setup do
135
+ @job.failed("OOOOPS!")
136
+ end
137
+
138
+ should "set status" do
139
+ assert_equal 'failed', @job.status.status
140
+ end
141
+
142
+ should "set message" do
143
+ assert_equal "OOOOPS!", @job.status.message
144
+ end
145
+ end
146
+
147
+ context "#completed" do
148
+ setup do
149
+ @job.completed
150
+ end
151
+
152
+ should "set status" do
153
+ assert_equal 'completed', @job.status.status
154
+ end
155
+
156
+ should "set message" do
157
+ assert_match(/complete/i, @job.status.message)
158
+ end
159
+
160
+ end
161
+
162
+ context "#safe_perform!" do
163
+ setup do
164
+ @job = ErrorJob.new("123")
165
+ assert_raises(RuntimeError) do
166
+ @job.safe_perform!
167
+ end
168
+ end
169
+
170
+ should "set status as failed" do
171
+ assert_equal 'failed', @job.status.status
172
+ end
173
+
174
+ end
175
+
176
+ end
177
+
178
+ end
179
+
180
+ end