delayed_job_groups 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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ delayed_job.sqlite3
2
+ *.swp
3
+ *.swo
4
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source :rubygems
2
+
3
+ gem 'rails'
4
+ gem 'delayed_job', :git => 'http://github.com/collectiveidea/delayed_job.git'
5
+
6
+ group :test do
7
+ gem 'rspec-rails'
8
+ gem 'sqlite3-ruby'
9
+ gem 'autotest'
10
+ gem 'autotest-fsevent'
11
+ gem 'autotest-growl'
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,106 @@
1
+ GIT
2
+ remote: http://github.com/collectiveidea/delayed_job.git
3
+ revision: aba9905764c2a13a110a272137d1ad9798fd55e0
4
+ specs:
5
+ delayed_job (2.1.0.pre2)
6
+ activesupport (~> 3.0)
7
+ daemons
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ abstract (1.0.0)
13
+ actionmailer (3.0.1)
14
+ actionpack (= 3.0.1)
15
+ mail (~> 2.2.5)
16
+ actionpack (3.0.1)
17
+ activemodel (= 3.0.1)
18
+ activesupport (= 3.0.1)
19
+ builder (~> 2.1.2)
20
+ erubis (~> 2.6.6)
21
+ i18n (~> 0.4.1)
22
+ rack (~> 1.2.1)
23
+ rack-mount (~> 0.6.12)
24
+ rack-test (~> 0.5.4)
25
+ tzinfo (~> 0.3.23)
26
+ activemodel (3.0.1)
27
+ activesupport (= 3.0.1)
28
+ builder (~> 2.1.2)
29
+ i18n (~> 0.4.1)
30
+ activerecord (3.0.1)
31
+ activemodel (= 3.0.1)
32
+ activesupport (= 3.0.1)
33
+ arel (~> 1.0.0)
34
+ tzinfo (~> 0.3.23)
35
+ activeresource (3.0.1)
36
+ activemodel (= 3.0.1)
37
+ activesupport (= 3.0.1)
38
+ activesupport (3.0.1)
39
+ arel (1.0.1)
40
+ activesupport (~> 3.0.0)
41
+ autotest (4.4.1)
42
+ autotest-fsevent (0.2.3)
43
+ sys-uname
44
+ autotest-growl (0.2.6)
45
+ builder (2.1.2)
46
+ daemons (1.1.0)
47
+ diff-lcs (1.1.2)
48
+ erubis (2.6.6)
49
+ abstract (>= 1.0.0)
50
+ i18n (0.4.2)
51
+ mail (2.2.9)
52
+ activesupport (>= 2.3.6)
53
+ i18n (~> 0.4.1)
54
+ mime-types (~> 1.16)
55
+ treetop (~> 1.4.8)
56
+ mime-types (1.16)
57
+ polyglot (0.3.1)
58
+ rack (1.2.1)
59
+ rack-mount (0.6.13)
60
+ rack (>= 1.0.0)
61
+ rack-test (0.5.6)
62
+ rack (>= 1.0)
63
+ rails (3.0.1)
64
+ actionmailer (= 3.0.1)
65
+ actionpack (= 3.0.1)
66
+ activerecord (= 3.0.1)
67
+ activeresource (= 3.0.1)
68
+ activesupport (= 3.0.1)
69
+ bundler (~> 1.0.0)
70
+ railties (= 3.0.1)
71
+ railties (3.0.1)
72
+ actionpack (= 3.0.1)
73
+ activesupport (= 3.0.1)
74
+ rake (>= 0.8.4)
75
+ thor (~> 0.14.0)
76
+ rake (0.8.7)
77
+ rspec (2.0.1)
78
+ rspec-core (~> 2.0.1)
79
+ rspec-expectations (~> 2.0.1)
80
+ rspec-mocks (~> 2.0.1)
81
+ rspec-core (2.0.1)
82
+ rspec-expectations (2.0.1)
83
+ diff-lcs (>= 1.1.2)
84
+ rspec-mocks (2.0.1)
85
+ rspec-core (~> 2.0.1)
86
+ rspec-expectations (~> 2.0.1)
87
+ rspec-rails (2.0.1)
88
+ rspec (~> 2.0.0)
89
+ sqlite3-ruby (1.3.1)
90
+ sys-uname (0.8.4)
91
+ thor (0.14.3)
92
+ treetop (1.4.8)
93
+ polyglot (>= 0.3.1)
94
+ tzinfo (0.3.23)
95
+
96
+ PLATFORMS
97
+ ruby
98
+
99
+ DEPENDENCIES
100
+ autotest
101
+ autotest-fsevent
102
+ autotest-growl
103
+ delayed_job!
104
+ rails
105
+ rspec-rails
106
+ sqlite3-ruby
data/README.markdown ADDED
@@ -0,0 +1,78 @@
1
+ delayed job groups
2
+ ==================
3
+
4
+ Adds grouping to jobs. Only 1 job in each group will be executed regardless of the number of workers.
5
+
6
+
7
+ Requires
8
+ --------
9
+
10
+ * rails 3
11
+ * Latest version of delayed_job from github - current release(v2.1.0.pre2) does not support enqueue hooks
12
+ * active_record backend - other backends aren't supported'
13
+
14
+
15
+ Install
16
+ -------
17
+
18
+ # Gemfile
19
+ gem 'delayed_job_groups', :require => false
20
+
21
+ # application.rb
22
+ AppName::Application.initialize!
23
+ require 'delayed_job_groups; # must be loaded after delayed job has guessed backend
24
+
25
+ Add migration to add lock_group column
26
+
27
+ # db/migrate/xxx_add_lock_group_to_delayed_jobs
28
+ class AddLockGroupToDelayedJobs < ActiveRecord::Migration
29
+ def self.up
30
+ add_column :delayed_jobs, :lock_group, :string
31
+ end
32
+
33
+ def self.down
34
+ remove_column :delayed_jobs, :lock_group
35
+ end
36
+ end
37
+
38
+
39
+ Usage
40
+ -----
41
+
42
+ Job groups are strings. You need to specify what the job_group should be in a block. Delayed job will only perform 1 job from each group at a time.
43
+
44
+ ### Job groups for standard jobs ###
45
+
46
+ class ResizeImageJob < Struct.new(:format)
47
+ job_group{ |resize_image_job| resize_image_job.format }
48
+
49
+ def perform
50
+ resize_to format
51
+ end
52
+ end
53
+
54
+
55
+ ### Job groups when using delay() ###
56
+
57
+ class Person < ActiveRecord::Base
58
+ job_group{ |person| person.role }
59
+
60
+ def send_welcome
61
+ ...
62
+ end
63
+ end
64
+
65
+ Person.create(:role => "admin").delay.send_welcome
66
+
67
+ ### Job groups when methods are declared asynchonous ###
68
+
69
+ class Person < ActiveRecord::Base
70
+ job_group{ |person| person.role }
71
+
72
+ def send_welcome
73
+ ...
74
+ end
75
+ handle_asynchronously :send_welcome
76
+ end
77
+
78
+ Person.create(:role => "admin").send_welcome
data/Rakefile.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "delayed_job_groups"
8
+ gem.summary = %Q{Adds job groups to delayed_job}
9
+ gem.description = %Q{Adds job groups to delayed_job}
10
+ gem.email = "oliver@opsb.co.uk"
11
+ gem.homepage = "http://github.com/opsb/delayed_job_groups"
12
+ gem.authors = ["opsb"]
13
+ end
14
+ Jeweler::GemcutterTasks.new
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
17
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,53 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile.rb, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{delayed_job_groups}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["opsb"]
12
+ s.date = %q{2010-11-02}
13
+ s.description = %q{Adds job groups to delayed_job}
14
+ s.email = %q{oliver@opsb.co.uk}
15
+ s.extra_rdoc_files = [
16
+ "README.markdown"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "README.markdown",
23
+ "Rakefile.rb",
24
+ "VERSION",
25
+ "delayed_job_groups.gemspec",
26
+ "lib/delayed_job_groups.rb",
27
+ "lib/delayed_job_groups/active_record_groups.rb",
28
+ "lib/delayed_job_groups/delayed_job_groups.rb",
29
+ "spec/database.yml",
30
+ "spec/delayed_job_groups_spec.rb",
31
+ "spec/spec_helper.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/opsb/delayed_job_groups}
34
+ s.rdoc_options = ["--charset=UTF-8"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.3.7}
37
+ s.summary = %q{Adds job groups to delayed_job}
38
+ s.test_files = [
39
+ "spec/delayed_job_groups_spec.rb",
40
+ "spec/spec_helper.rb"
41
+ ]
42
+
43
+ if s.respond_to? :specification_version then
44
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ else
49
+ end
50
+ else
51
+ end
52
+ end
53
+
@@ -0,0 +1,23 @@
1
+ class ActiveRecord::Base
2
+ class << self
3
+ def job_group(&block)
4
+ @lock_group_factory = block
5
+ end
6
+
7
+ def has_job_groups?
8
+ !!@lock_group_factory
9
+ end
10
+
11
+ def lock_group(payload)
12
+ @lock_group_factory.call(payload)
13
+ end
14
+ end
15
+
16
+ def enqueue(job)
17
+ target = job.payload_object.class == ::Delayed::PerformableMethod ? job.payload_object.object : job.payload_object
18
+ if target.class.has_job_groups?
19
+ job.lock_group = target.class.lock_group(target)
20
+ job.save
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'delayed_job'
2
+
3
+ class Delayed::Backend::ActiveRecord::Job
4
+ scope :in_unlocked_group, lambda{
5
+ delayed_jobs = self.table_name
6
+ unlocked_groups_select = "select distinct #{delayed_jobs}.lock_group from #{delayed_jobs} where #{delayed_jobs}.locked_by is not null"
7
+ where("#{delayed_jobs}.lock_group not in (#{unlocked_groups_select}) or #{delayed_jobs}.lock_group is null")
8
+ }
9
+ scope :orig_ready_to_run, scopes[:ready_to_run]
10
+ scope :ready_to_run, lambda{ |*args|
11
+ orig_ready_to_run(*args).
12
+ in_unlocked_group
13
+ }
14
+ end
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/delayed_job_groups/active_record_groups'
2
+ require File.dirname(__FILE__) + '/delayed_job_groups/delayed_job_groups'
data/spec/database.yml ADDED
@@ -0,0 +1,3 @@
1
+ sqlite:
2
+ adapter: sqlite3
3
+ database: delayed_job.sqlite3
@@ -0,0 +1,93 @@
1
+ require 'spec/spec_helper'
2
+
3
+ ActiveRecord::Schema.define do
4
+ create_table :grouped_jobs, :force => true do |table|
5
+ table.string :repository
6
+ end
7
+ create_table :simple_jobs, :force => true do |table|
8
+ end
9
+ create_table :users, :force => true do |table|
10
+ table.string :role
11
+ end
12
+ end
13
+
14
+ class GroupedJob < ActiveRecord::Base
15
+ job_group{ |simple_job| simple_job.repository }
16
+
17
+ def perform
18
+ puts "running grouped job"
19
+ end
20
+ end
21
+
22
+ class SimpleJob < ActiveRecord::Base
23
+ def perform
24
+ puts "running simple job"
25
+ end
26
+ end
27
+
28
+ class User < ActiveRecord::Base
29
+ job_group{ |user| user.role }
30
+ def send_welcome_email
31
+ puts "thanking user"
32
+ end
33
+ handle_asynchronously :send_welcome_email
34
+ def expensive_operation
35
+ puts "working hard"
36
+ end
37
+ end
38
+
39
+ describe Delayed::Job do
40
+ MAX_RUN_TIME = 4000 # seconds? TBC
41
+ WORKER = 'name_of_worker'
42
+
43
+ context "with 2 jobs in the same group, one locked, one unlocked and 1 job in a different group" do
44
+ before do
45
+ 2.times{ Delayed::Job.enqueue GroupedJob.new(:repository => "repo1") }
46
+ 1.times{ Delayed::Job.enqueue GroupedJob.new(:repository => "repo2") }
47
+ Delayed::Job.first.lock_exclusively!(MAX_RUN_TIME, WORKER)
48
+ end
49
+
50
+ it "should find no jobs that are ready to run" do
51
+ Delayed::Job.ready_to_run(WORKER, MAX_RUN_TIME).count.should == 1
52
+ end
53
+ end
54
+
55
+ context "job with no group" do
56
+ before do
57
+ Delayed::Job.enqueue SimpleJob.new
58
+ end
59
+ it "should still be queuable" do
60
+ Delayed::Job.ready_to_run(WORKER, MAX_RUN_TIME).count.should == 1
61
+ end
62
+ end
63
+
64
+ context "with 2 jobs in the same group, from methods declared as asynchronous, one unlocked and 1 job in a different group" do
65
+ before do
66
+ 2.times do
67
+ User.create(:role => "admin").send_welcome_email
68
+ end
69
+ 1.times{ Delayed::Job.enqueue GroupedJob.new(:repository => "repo2") }
70
+ Delayed::Job.first.lock_exclusively!(MAX_RUN_TIME, WORKER)
71
+
72
+ end
73
+
74
+ it "should find no jobs that are ready to run" do
75
+ Delayed::Job.ready_to_run(WORKER, MAX_RUN_TIME).count.should == 1
76
+ end
77
+ end
78
+
79
+ context "with 2 jobs in the same group, from delay() calls, one unlocked and 1 job in a different group" do
80
+ before do
81
+ 2.times do
82
+ User.create(:role => "admin").delay.expensive_operation
83
+ end
84
+ 1.times{ Delayed::Job.enqueue GroupedJob.new(:repository => "repo2") }
85
+ Delayed::Job.first.lock_exclusively!(MAX_RUN_TIME, WORKER)
86
+
87
+ end
88
+
89
+ it "should find no jobs that are ready to run" do
90
+ Delayed::Job.ready_to_run(WORKER, MAX_RUN_TIME).count.should == 1
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,56 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'logger'
6
+
7
+
8
+
9
+ ENV['RAILS_ENV'] = 'test'
10
+ require 'rails'
11
+
12
+ require 'active_record'
13
+ config = YAML.load(File.read('spec/database.yml'))
14
+ ActiveRecord::Base.configurations = {'test' => config['sqlite']}
15
+ ActiveRecord::Base.establish_connection
16
+ ActiveRecord::Migration.verbose = false
17
+
18
+ ActiveRecord::Schema.define do
19
+ create_table :delayed_jobs, :force => true do |table|
20
+ table.integer :priority, :default => 0
21
+ table.integer :attempts, :default => 0
22
+ table.text :handler
23
+ table.text :last_error
24
+ table.datetime :run_at
25
+ table.datetime :locked_at
26
+ table.datetime :failed_at
27
+ table.string :locked_by
28
+ table.string :lock_group
29
+ table.timestamps
30
+
31
+ table.integer :queue_id
32
+ end
33
+ end
34
+
35
+ require 'rspec'
36
+ require 'delayed_job'
37
+
38
+ Delayed::Worker.logger = Logger.new('/tmp/dj.log')
39
+ ActiveRecord::Base.logger = Delayed::Worker.logger
40
+ Delayed::Worker.backend = :active_record
41
+
42
+ require 'delayed_job_groups'
43
+ RSpec.configure do |config|
44
+ config.before do
45
+ ActiveRecord::Base.connection.increment_open_transactions
46
+ ActiveRecord::Base.connection.transaction_joinable = false
47
+ ActiveRecord::Base.connection.begin_db_transaction
48
+ end
49
+ config.after do
50
+ if ActiveRecord::Base.connection.open_transactions != 0
51
+ ActiveRecord::Base.connection.rollback_db_transaction
52
+ ActiveRecord::Base.connection.decrement_open_transactions
53
+ end
54
+ ActiveRecord::Base.clear_active_connections!
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: delayed_job_groups
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - opsb
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-02 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Adds job groups to delayed_job
23
+ email: oliver@opsb.co.uk
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.markdown
30
+ files:
31
+ - .gitignore
32
+ - Gemfile
33
+ - Gemfile.lock
34
+ - README.markdown
35
+ - Rakefile.rb
36
+ - VERSION
37
+ - delayed_job_groups.gemspec
38
+ - lib/delayed_job_groups.rb
39
+ - lib/delayed_job_groups/active_record_groups.rb
40
+ - lib/delayed_job_groups/delayed_job_groups.rb
41
+ - spec/database.yml
42
+ - spec/delayed_job_groups_spec.rb
43
+ - spec/spec_helper.rb
44
+ has_rdoc: true
45
+ homepage: http://github.com/opsb/delayed_job_groups
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options:
50
+ - --charset=UTF-8
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.7
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Adds job groups to delayed_job
78
+ test_files:
79
+ - spec/delayed_job_groups_spec.rb
80
+ - spec/spec_helper.rb