delayed_job_recurring 0.3.4 → 0.3.9

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.
Files changed (4) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +48 -2
  3. data/lib/delayed/recurring_job.rb +43 -54
  4. metadata +27 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 290117f54a785d30a82b864887404a17726190ed
4
- data.tar.gz: 81e2bab83a90f6022e9345a27595d0f57c688b1b
2
+ SHA256:
3
+ metadata.gz: d2df13749a11ec5a5a5fef3f60eb7c7a1216e13a6b93a6e084392a30b0fabefd
4
+ data.tar.gz: 98bbe52c01ef1a79e4ce2c512a47d91e4a9380b8d119fc05605e13a27f805425
5
5
  SHA512:
6
- metadata.gz: 195de5c332484916371e1389c485204e98274428cd093423e0b8058823aa6f8067a0f10c1437ff7b79b83b643eb30df27c705bb2ff12e8baadf356f157b01f51
7
- data.tar.gz: e6210b3ba0b09c7bfecfbddba72f779305a51645792adb01f6da8a1ebf2f9f8940b04c36933a588018c2bf5ab8a74ee04b393c4b6f6fbf8d6c08845c5cf7f8bf
6
+ metadata.gz: ec8ae92ce900948c73831b5b965e603032ee645e134b410af15f1e1b5392b5b3630252acac34ced89e3ff71d1334a37b7bd3fed212dabcc47d2ab37ee44d1294
7
+ data.tar.gz: bb8f9c77c3d0417b1e35861d7f81c8e8c82eb10963bdb32ffeef0b14f87cdfa2c8430259ddd8b7d494922434f6d38b1f8cb9f587f10373155218adec14cf36ae
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # delayed\_job\_recurring
2
+ [![Build Status](https://travis-ci.org/amitree/delayed_job_recurring.svg)](https://travis-ci.org/amitree/delayed_job_recurring)
2
3
 
3
4
  Extends delayed\_job to support recurring jobs.
4
5
 
@@ -27,12 +28,41 @@ class MyTask
27
28
  end
28
29
  ```
29
30
 
30
- And schedule it. In a rails app, you might put this in an initializer:
31
+ Finally, schedule it:
31
32
 
32
33
  ```ruby
33
34
  MyTask.schedule! # run every day at 11am Pacific time (accounting for daylight savings)
34
35
  ```
35
36
 
37
+ The best practice is to add your `MyTask.schedule!` lines to a rake file, e.g.
38
+
39
+ ```ruby
40
+ # lib/tasks/recurring_jobs.rake
41
+
42
+ namespace :recurring do
43
+ task init: :environment do
44
+ MyTask.schedule!
45
+ MyOtherTask.schedule!
46
+
47
+ if Rails.env.production?
48
+ MyProductionOnlyTask.schedule!
49
+ end
50
+ end
51
+ end
52
+ ```
53
+
54
+ and invoke this job by running `rake recurring:init` on each deployment.
55
+
56
+ Alternatively, if your app only has one instance running, you can put your
57
+ `schedule!` calls into an initializer, and then your jobs will be automatically
58
+ scheduled when your app starts. However, if you have more than one instance of
59
+ your app running in production, this will lead to a race condition and you will
60
+ end up with duplicate recurring jobs in the queue.
61
+
62
+ ## ActiveJob
63
+
64
+ Note: your task class should **not** inherit from ActiveJob::Base.
65
+
36
66
  ## Advanced usage
37
67
 
38
68
  ### Passing options to schedule
@@ -44,7 +74,7 @@ MyTask.schedule(run_at: '12:00')
44
74
  ### Running at multiples times each day
45
75
 
46
76
  ```ruby
47
- MyTask.schedule(run_every: 1.day, run_at: ['11:00', '6:00pm']
77
+ MyTask.schedule(run_every: 1.day, run_at: ['11:00', '6:00pm'])
48
78
  ```
49
79
 
50
80
  ### Running on specific days of the week
@@ -53,6 +83,22 @@ MyTask.schedule(run_every: 1.day, run_at: ['11:00', '6:00pm']
53
83
  MyTask.schedule(run_every: 1.week, run_at: ['sunday 8:00am', 'wednesday 8:00am'])
54
84
  ```
55
85
 
86
+ ### Scheduling multiple jobs of same class
87
+
88
+ By default, before scheduling a new job, the old jobs scheduled with the same class will be unscheduled.
89
+
90
+ To schedule multiple jobs with same class, pass an unique matching param `job_matching_param` and value for that matching param in each job as below:
91
+
92
+ ```ruby
93
+ MyTask.schedule(run_at: '12:00', job_matching_param: 'schedule_id', schedule_id: 2)
94
+ ```
95
+
96
+ This allows you to schedule multiple jobs with same class if value of the unique matching param(which is `schedule_id` in above example) is different in each job.
97
+
56
98
  ## Thanks!
57
99
 
58
100
  Many thanks to @ginjo and @kares for their work! This code was derived from https://gist.github.com/ginjo/3688965.
101
+
102
+ ## Contributing
103
+
104
+ [![Open Source Helpers](https://www.codetriage.com/amitree/delayed_job_recurring/badges/users.svg)](https://www.codetriage.com/amitree/delayed_job_recurring)
@@ -23,13 +23,17 @@ module Delayed
23
23
 
24
24
  # Schedule this "repeating" job
25
25
  def schedule! options = {}
26
- options = options.dup
26
+ options = options.dup.reverse_merge(@schedule_options || {})
27
+
28
+ if options[:new_instance] && !options.delete(:reentry)
29
+ return self.class.new.schedule! options.merge(reentry: true)
30
+ end
27
31
 
28
32
  if run_every = options.delete(:run_every)
29
33
  options[:run_interval] = serialize_duration(run_every)
30
34
  end
31
35
 
32
- @schedule_options = options.reverse_merge(@schedule_options || {}).reverse_merge(
36
+ @schedule_options = options.reverse_merge(
33
37
  run_at: self.class.run_at,
34
38
  timezone: self.class.timezone,
35
39
  run_interval: serialize_duration(self.class.run_every),
@@ -40,10 +44,13 @@ module Delayed
40
44
  enqueue_opts = { priority: @schedule_options[:priority], run_at: next_run_time }
41
45
  enqueue_opts[:queue] = @schedule_options[:queue] if @schedule_options[:queue]
42
46
 
43
- if Gem.loaded_specs['delayed_job'].version.to_s.first.to_i < 3
44
- Delayed::Job.enqueue self, enqueue_opts[:priority], enqueue_opts[:run_at]
45
- else
46
- Delayed::Job.enqueue self, enqueue_opts
47
+ Delayed::Job.transaction do
48
+ self.class.jobs(@schedule_options).destroy_all
49
+ if Gem.loaded_specs['delayed_job'].version.to_s.first.to_i < 3
50
+ Delayed::Job.enqueue self, enqueue_opts[:priority], enqueue_opts[:run_at]
51
+ else
52
+ Delayed::Job.enqueue self, enqueue_opts
53
+ end
47
54
  end
48
55
  end
49
56
 
@@ -157,77 +164,59 @@ module Delayed
157
164
  end
158
165
 
159
166
  # Show all jobs for this schedule
160
- def jobs
161
- ::Delayed::Job.where("(handler LIKE ?) OR (handler LIKE ?)", "--- !ruby/object:#{name} %", "--- !ruby/object:#{name}\n%")
167
+ def jobs(options = {})
168
+ options = options.with_indifferent_access
169
+
170
+ # Construct dynamic query with 'job_matching_param' if present
171
+ query = ["((handler LIKE ?) OR (handler LIKE ?))", "--- !ruby/object:#{name} %", "--- !ruby/object:#{name}\n%"]
172
+ if options[:job_matching_param].present?
173
+ matching_key = options[:job_matching_param]
174
+ matching_value = options[matching_key]
175
+ matching_yaml = yaml_quote(matching_value)
176
+ query[0] = "#{query[0]} AND handler LIKE ?"
177
+ query << "%#{matching_key}: #{matching_yaml}%"
178
+ end
179
+
180
+ ::Delayed::Job.where(query)
162
181
  end
163
182
 
164
183
  # Remove all jobs for this schedule (Stop the schedule)
165
- def unschedule
166
- jobs.each{|j| j.destroy}
184
+ def unschedule(options = {})
185
+ jobs(options).each{|j| j.destroy}
167
186
  end
168
187
 
169
188
  # Main interface to start this schedule (adds it to the jobs table).
170
189
  # Pass in a time to run the first job (nil runs the first job at run_interval from now).
171
190
  def schedule(options = {})
172
- schedule!(options) unless scheduled?
191
+ schedule!(options) unless scheduled?(options)
173
192
  end
174
193
 
175
194
  def schedule!(options = {})
176
195
  return unless Delayed::Worker.delay_jobs
177
- unschedule
178
- new.schedule!(options)
196
+ unschedule(options)
197
+ new.schedule!(options.merge(new_instance: true))
179
198
  end
180
199
 
181
- def scheduled?
182
- jobs.count > 0
200
+ def scheduled?(options = {})
201
+ jobs(options).count > 0
183
202
  end
184
203
 
185
204
  def inherited(subclass)
186
- %i(@run_at @run_interval @tz @priority).each do |var|
205
+ [:@run_at, :@run_interval, :@tz, :@priority].each do |var|
187
206
  next unless instance_variable_defined? var
188
207
  subclass.instance_variable_set var, self.instance_variable_get(var)
189
208
  subclass.instance_variable_set "#{var}_inherited", true
190
209
  end
191
210
  end
192
211
 
212
+ private
213
+ def yaml_quote(value)
214
+ # In order to ensure matching indentation, place the element inside a
215
+ # two-level hash (the first level mimicking 'schedule_options', the second
216
+ # for #{job_matching_param}), and strip out the leading "---\n:a:\n :a: "
217
+ # but keep the trailing newline.
218
+ ({a: {a: value}}).to_yaml[14..-1]
219
+ end
193
220
  end # ClassMethods
194
221
  end # RecurringJob
195
-
196
- module Task
197
- # Creates a new class wrapper around a block of code to be scheduled.
198
- def self.new(name, options, &block)
199
- task_class = Class.new
200
- task_class.class_eval do
201
- include Delayed::RecurringJob
202
-
203
- def display_name
204
- self.class.name
205
- end
206
-
207
- def perform
208
- block.call
209
- end
210
- end
211
-
212
- Object.const_set(name, task_class) if name
213
- task_class.schedule(options)
214
- return task_class
215
- end
216
-
217
- # Schedule a block of code on-the-fly.
218
- # This is a friendly wrapper for using Task.new without an explicit constant assignment.
219
- # Delayed::Task.schedule('MyNewTask', run_every: 10.minutes, run_at: 1.minute.from_now){do_some_stuff_here}
220
- # or
221
- # Delayed::Task.schedule(run_every: 10.minutes, run_at: 1.minute.from_now){do_some_stuff_here}
222
- def self.schedule(name_or_options={}, options={}, &block)
223
- case name_or_options
224
- when Hash
225
- name, options = nil, name_or_options
226
- else
227
- name = name_or_options
228
- end
229
-
230
- self.new name, options, &block
231
- end
232
- end # Task
233
222
  end # Delayed
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed_job_recurring
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Novak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-22 00:00:00.000000000 Z
11
+ date: 2020-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,34 +24,48 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rspec
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - '='
32
46
  - !ruby/object:Gem::Version
33
- version: 3.0.0
47
+ version: 3.6.0
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - '='
39
53
  - !ruby/object:Gem::Version
40
- version: 3.0.0
54
+ version: 3.6.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec-rails
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - '='
46
60
  - !ruby/object:Gem::Version
47
- version: 3.0.1
61
+ version: 3.6.1
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - '='
53
67
  - !ruby/object:Gem::Version
54
- version: 3.0.1
68
+ version: 3.6.1
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: sqlite3
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -100,28 +114,28 @@ dependencies:
100
114
  requirements:
101
115
  - - ">="
102
116
  - !ruby/object:Gem::Version
103
- version: '4.0'
117
+ version: '3.0'
104
118
  type: :runtime
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - ">="
109
123
  - !ruby/object:Gem::Version
110
- version: '4.0'
124
+ version: '3.0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: delayed_job_active_record
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - ">="
116
130
  - !ruby/object:Gem::Version
117
- version: '4.0'
131
+ version: '0'
118
132
  type: :runtime
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
136
  - - ">="
123
137
  - !ruby/object:Gem::Version
124
- version: '4.0'
138
+ version: '0'
125
139
  description: Extends delayed_job to support recurring jobs, including timezone support
126
140
  email: engineering@amitree.com
127
141
  executables: []
@@ -142,17 +156,16 @@ require_paths:
142
156
  - lib
143
157
  required_ruby_version: !ruby/object:Gem::Requirement
144
158
  requirements:
145
- - - "~>"
159
+ - - ">"
146
160
  - !ruby/object:Gem::Version
147
- version: '2.0'
161
+ version: '1.9'
148
162
  required_rubygems_version: !ruby/object:Gem::Requirement
149
163
  requirements:
150
164
  - - ">="
151
165
  - !ruby/object:Gem::Version
152
166
  version: '0'
153
167
  requirements: []
154
- rubyforge_project:
155
- rubygems_version: 2.2.2
168
+ rubygems_version: 3.0.6
156
169
  signing_key:
157
170
  specification_version: 4
158
171
  summary: Recurring jobs for delayed_job