ryansch-resque-loner 1.0.1.1 → 1.0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ **.DS_Store
3
+ **.swp
4
+ Gemfile.lock
5
+ .rvmrc
@@ -0,0 +1,7 @@
1
+ 1.0.1
2
+ --------------------------------
3
+ Pulled in #8 and #9 so that removing empty queues
4
+ does not fail
5
+
6
+ 1.0
7
+ ---------------------------------
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
3
+
4
+ group :development do
5
+ gem 'ruby-debug', :platform => :mri_18
6
+ gem 'ruby-debug19', :platform => :mri_19
7
+ end
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Moviepilot GmbH http://moviepilot.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -68,13 +68,6 @@ Since resque-loner keeps track of which jobs are queued in a way that allows for
68
68
  >> Resque.enqueued_in? :another_queue, CacheSweeper, 1
69
69
  => false
70
70
 
71
- If you want the same type of job in different queues, resque-loner lets you enqueue/dequeue to a queue of your choice:
72
-
73
- >> Resque.enqueue_to :another_queue, CacheSweeper, 1
74
- => "OK"
75
- >> Resqueue.dequeue_from :another_queue, CacheSweeper, 1
76
- => 1
77
-
78
71
  How it works
79
72
  --------
80
73
 
@@ -0,0 +1,83 @@
1
+ #
2
+ # Setup
3
+ #
4
+
5
+ $LOAD_PATH.unshift 'lib'
6
+
7
+ require "rubygems"
8
+ require "bundler"
9
+ Bundler.setup
10
+
11
+ require 'rspec/core/rake_task'
12
+
13
+ load 'tasks/redis.rake'
14
+ require 'rake/testtask'
15
+
16
+ require 'resque/tasks'
17
+
18
+ require 'bundler/gem_tasks'
19
+
20
+ def command?(command)
21
+ system("type #{command} > /dev/null 2>&1")
22
+ end
23
+
24
+
25
+ #
26
+ # Tests
27
+ #
28
+
29
+ task :default => :spec
30
+
31
+ desc "Run specs for resque-loner"
32
+ RSpec::Core::RakeTask.new(:spec) do |t|
33
+ t.pattern = "spec/**/*_spec.rb"
34
+ t.rspec_opts = %w(-fd -c)
35
+ end
36
+
37
+ # desc "Run resque's test suite to make sure we did not break anything"
38
+ # task :test do
39
+ # rg = command?(:rg)
40
+ # Dir['test/**/*_test.rb'].each do |f|
41
+ # rg ? sh("rg #{f}") : ruby(f)
42
+ # end
43
+ # end
44
+
45
+ if command?(:rg)
46
+ desc "Run the test suite with rg"
47
+ task :test do
48
+ Dir['test/**/*_test.rb'].each do |f|
49
+ sh("rg #{f}")
50
+ end
51
+ end
52
+ else
53
+ Rake::TestTask.new do |test|
54
+ test.libs << "test"
55
+ test.test_files = FileList['test/**/*_test.rb']
56
+ end
57
+ end
58
+
59
+ if command? :kicker
60
+ desc "Launch Kicker (like autotest)"
61
+ task :kicker do
62
+ puts "Kicking... (ctrl+c to cancel)"
63
+ exec "kicker -e rake test lib examples"
64
+ end
65
+ end
66
+
67
+
68
+ #
69
+ # Install
70
+ #
71
+
72
+ task :install => [ 'redis:install', 'dtach:install' ]
73
+
74
+
75
+ #
76
+ # Documentation
77
+ #
78
+
79
+ begin
80
+ require 'sdoc_helpers'
81
+ rescue LoadError
82
+ end
83
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rails/init.rb'
@@ -1,7 +1,7 @@
1
1
  module Resque
2
2
  module Plugins
3
3
  module Loner
4
- VERSION = "1.0.1.1"
4
+ VERSION = "1.0.1.2"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1 @@
1
+ require 'resque-loner'
@@ -0,0 +1,50 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+
5
+ require 'resque-loner/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'ryansch-resque-loner'
9
+ s.version = Resque::Plugins::Loner::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.authors = ['Jannis Hermanns', 'Ryan Schlesinger']
12
+ s.email = ['jannis@moviepilot.com', 'ryan@instanceinc.com']
13
+ s.homepage = 'http://github.com/ryansch/resque-loner'
14
+ s.summary = 'Adds unique jobs to resque'
15
+ s.has_rdoc = false
16
+
17
+ s.rubyforge_project = 'resque-loner'
18
+
19
+ s.add_dependency 'resque', '~>1.0'
20
+ {
21
+ 'rake' => '> 0.8.7',
22
+ 'rack-test' => '~> 0.5.7',
23
+ 'rspec' => '~> 2.5.0',
24
+ 'mock_redis' => '~> 0.2.0',
25
+ 'yajl-ruby' => '~> 0.8.2'
26
+ }.each do |lib, version|
27
+ s.add_development_dependency lib, version
28
+ end
29
+
30
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
31
+ s.files = `git ls-files`.split("\n")
32
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
33
+ s.require_paths = ["lib"]
34
+
35
+ s.description = <<desc
36
+ Makes sure that for special jobs, there can be only one job with the same workload in one queue.
37
+
38
+ Example:
39
+ class CacheSweeper
40
+
41
+ include Resque::Plugins::UniqueJob
42
+
43
+ @queue = :cache_sweeps
44
+
45
+ def self.perform(article_id)
46
+ # Cache Me If You Can...
47
+ end
48
+ end
49
+ desc
50
+ end
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ #
5
+ # Resque-loner specific specs. I'm shooting right through the stack here and just
6
+ # test the outcomes, because the implementation will change soon and the tests run
7
+ # quite quickly.
8
+ #
9
+
10
+ class SomeJob
11
+ @queue = :some_queue
12
+ end
13
+
14
+ class SomeUniqueJob
15
+
16
+ include Resque::Plugins::UniqueJob
17
+
18
+ @queue = :other_queue
19
+ def self.perform(foo); end
20
+ end
21
+
22
+ class FailingUniqueJob
23
+ include Resque::Plugins::UniqueJob
24
+ @queue = :other_queue
25
+ def self.perform(foo)
26
+ raise "I beg to differ"
27
+ end
28
+ end
29
+
30
+ class DeprecatedUniqueJob < Resque::Plugins::Loner::UniqueJob
31
+
32
+ @queue = :other_queue
33
+ def self.perform(foo); end
34
+ end
35
+
36
+ describe "Resque" do
37
+
38
+ before(:each) do
39
+ Resque.redis.flushall
40
+ Resque.size(:other_queue).should == 0
41
+ Resque.size(:some_queue).should == 0
42
+ end
43
+
44
+ describe "Jobs" do
45
+ it "can put multiple normal jobs on a queue" do
46
+ Resque.enqueue SomeJob, "foo"
47
+ Resque.enqueue SomeJob, "foo"
48
+ Resque.size(:some_queue).should == 2
49
+ end
50
+
51
+ it "should allow only one of the same job to sit in a queue" do
52
+ Resque.enqueue SomeUniqueJob, "foo"
53
+ Resque.enqueue SomeUniqueJob, "foo"
54
+ Resque.size(:other_queue).should == 1
55
+ end
56
+
57
+ it "should support deprecated Resque::Plugins::Loner::UniqueJob class" do
58
+ Resque.enqueue DeprecatedUniqueJob, "foo"
59
+ Resque.enqueue DeprecatedUniqueJob, "foo"
60
+ Resque.size(:other_queue).should == 1
61
+ end
62
+
63
+ it "should allow the same jobs to be executed one after the other" do
64
+ Resque.enqueue SomeUniqueJob, "foo"
65
+ Resque.enqueue SomeUniqueJob, "foo"
66
+ Resque.size(:other_queue).should == 1
67
+
68
+ Resque.reserve(:other_queue)
69
+ Resque.size(:other_queue).should == 0
70
+
71
+ Resque.enqueue SomeUniqueJob, "foo"
72
+ Resque.enqueue SomeUniqueJob, "foo"
73
+ Resque.size(:other_queue).should == 1
74
+ end
75
+
76
+ it "should be robust regarding hash attributes" do
77
+ Resque.enqueue SomeUniqueJob, :bar => 1, :foo => 2
78
+ Resque.enqueue SomeUniqueJob, :foo => 2, :bar => 1
79
+ Resque.size(:other_queue).should == 1
80
+ end
81
+
82
+ it "should be robust regarding hash attributes (JSON does not distinguish between string and symbol)" do
83
+ Resque.enqueue SomeUniqueJob, :bar => 1, :foo => 1
84
+ Resque.enqueue SomeUniqueJob, :bar => 1, "foo" => 1
85
+ Resque.size(:other_queue).should == 1
86
+ end
87
+
88
+ it "should mark jobs as unqueued, when Job.destroy is killing them" do
89
+ Resque.enqueue SomeUniqueJob, "foo"
90
+ Resque.enqueue SomeUniqueJob, "foo"
91
+ Resque.size(:other_queue).should == 1
92
+
93
+ Resque::Job.destroy(:other_queue, SomeUniqueJob)
94
+ Resque.size(:other_queue).should == 0
95
+
96
+ Resque.enqueue SomeUniqueJob, "foo"
97
+ Resque.enqueue SomeUniqueJob, "foo"
98
+ Resque.size(:other_queue).should == 1
99
+ end
100
+
101
+ it "should mark jobs as unqueued, when they raise an exception during #perform" do
102
+ 2.times { Resque.enqueue( FailingUniqueJob, "foo" ) }
103
+ Resque.size(:other_queue).should == 1
104
+
105
+ worker = Resque::Worker.new(:other_queue)
106
+ worker.work 0
107
+ Resque.size(:other_queue).should == 0
108
+
109
+ 2.times { Resque.enqueue( FailingUniqueJob, "foo" ) }
110
+ Resque.size(:other_queue).should == 1
111
+ end
112
+
113
+ it "should report if a job is queued or not" do
114
+ Resque.enqueue SomeUniqueJob, "foo"
115
+ Resque.enqueued?(SomeUniqueJob, "foo").should be_true
116
+ Resque.enqueued?(SomeUniqueJob, "bar").should be_false
117
+ end
118
+
119
+ it "should report if a job is in a special queue or not" do
120
+ default_queue = SomeUniqueJob.instance_variable_get(:@queue)
121
+ SomeUniqueJob.instance_variable_set(:@queue, :special_queue)
122
+
123
+ Resque.enqueue SomeUniqueJob, "foo"
124
+ Resque.enqueued_in?( :special_queue, SomeUniqueJob, "foo").should be_true
125
+
126
+ SomeUniqueJob.instance_variable_set(:@queue, default_queue)
127
+
128
+ Resque.enqueued?( SomeUniqueJob, "foo").should be_false
129
+ end
130
+
131
+ it "should not be able to report if a non-unique job was enqueued" do
132
+ Resque.enqueued?(SomeJob).should be_nil
133
+ end
134
+
135
+ it "should cleanup all loners when a queue is destroyed" do
136
+ Resque.enqueue SomeUniqueJob, "foo"
137
+ Resque.enqueue FailingUniqueJob, "foo"
138
+
139
+ Resque.remove_queue(:other_queue)
140
+
141
+ Resque.enqueue(SomeUniqueJob, "foo")
142
+ Resque.size(:other_queue).should == 1
143
+ end
144
+
145
+ it 'should not raise an error when deleting an already empty queue' do
146
+ expect { Resque.remove_queue(:other_queue) }.to_not raise_error
147
+ end
148
+
149
+ end
150
+ end
@@ -0,0 +1,115 @@
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 ./spec/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 ./spec/
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