delayed_job_recurring_mongoid_uriji 0.3.8

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ceea8a2cd6361eefbbb68c3ac8cc549447608a71
4
+ data.tar.gz: a08114c53fc9a2312d5a7caedac85ce32207ab02
5
+ SHA512:
6
+ metadata.gz: b36f2c72cdfccd56057b0b1393b7d8dd584420979f867b94429e5b81c09429decb1c7f9388266969330638e1dc4b51a39210b53bcf1b848e39cfa05a55abac21
7
+ data.tar.gz: e78eb4f0d0c62a021a9b5fe061439c52d339fdabee9ab5efb7e3d1e26568c3495fd1e264c788877449357a67c4fed4ad27a32624392435a949b9cb4e69785f6a
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Amitree
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,104 @@
1
+ # delayed\_job\_recurring\_mongoid
2
+ [![Build Status](https://travis-ci.org/amitree/delayed_job_recurring.svg)](https://travis-ci.org/amitree/delayed_job_recurring)
3
+
4
+ Extends delayed\_job to support recurring jobs.
5
+
6
+ ## Usage
7
+
8
+ Add it to your Gemfile:
9
+
10
+ ```ruby
11
+ gem 'delayed_job_recurring'
12
+ ```
13
+
14
+ Then define a task class. We like the concept of
15
+ [interactors](http://eng.joingrouper.com/blog/2014/03/03/rails-the-missing-parts-interactors),
16
+ so we put our task classes in `app/interactors`. You could also put them in `lib` or even `app/models`.
17
+
18
+ ```ruby
19
+ class MyTask
20
+ include Delayed::RecurringJob
21
+ run_every 1.day
22
+ run_at '11:00am'
23
+ timezone 'US/Pacific'
24
+ queue 'slow-jobs'
25
+ def perform
26
+ # Do some work here!
27
+ end
28
+ end
29
+ ```
30
+
31
+ Finally, schedule it:
32
+
33
+ ```ruby
34
+ MyTask.schedule! # run every day at 11am Pacific time (accounting for daylight savings)
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
+
66
+ ## Advanced usage
67
+
68
+ ### Passing options to schedule
69
+
70
+ ```ruby
71
+ MyTask.schedule(run_at: '12:00')
72
+ ```
73
+
74
+ ### Running at multiples times each day
75
+
76
+ ```ruby
77
+ MyTask.schedule(run_every: 1.day, run_at: ['11:00', '6:00pm'])
78
+ ```
79
+
80
+ ### Running on specific days of the week
81
+
82
+ ```ruby
83
+ MyTask.schedule(run_every: 1.week, run_at: ['sunday 8:00am', 'wednesday 8:00am'])
84
+ ```
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
+
98
+ ## Thanks!
99
+
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)
@@ -0,0 +1,210 @@
1
+ # Delayed::RecurringJob
2
+ module Delayed
3
+ module RecurringJob
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ base.class_eval do
7
+ @@logger = Delayed::Worker.logger
8
+ cattr_reader :logger
9
+ end
10
+ end
11
+
12
+ def failure
13
+ schedule!
14
+ end
15
+
16
+ def success
17
+ schedule!
18
+ end
19
+
20
+ # Schedule this "repeating" job
21
+ def schedule! options = {}
22
+ options = options.dup
23
+
24
+ if run_every = options.delete(:run_every)
25
+ options[:run_interval] = serialize_duration(run_every)
26
+ end
27
+
28
+ @schedule_options = options.reverse_merge(@schedule_options || {}).reverse_merge(
29
+ run_at: self.class.run_at,
30
+ timezone: self.class.timezone,
31
+ run_interval: serialize_duration(self.class.run_every),
32
+ priority: self.class.priority,
33
+ queue: self.class.queue
34
+ )
35
+ enqueue_opts = { priority: @schedule_options[:priority], run_at: next_run_time }
36
+ enqueue_opts[:queue] = @schedule_options[:queue] if @schedule_options[:queue]
37
+
38
+ self.class.jobs(@schedule_options).destroy_all
39
+
40
+ if Gem.loaded_specs['delayed_job'].version.to_s.first.to_i < 3
41
+ Delayed::Job.enqueue self, enqueue_opts[:priority], enqueue_opts[:run_at]
42
+ else
43
+ Delayed::Job.enqueue self, enqueue_opts
44
+ end
45
+ end
46
+
47
+ def next_run_time
48
+ times = @schedule_options[:run_at]
49
+ times = [times] unless times.is_a? Array
50
+ times = times.map{|time| parse_time(time, @schedule_options[:timezone])}
51
+ times = times.map{|time| time.in_time_zone @schedule_options[:timezone]} if @schedule_options[:timezone]
52
+
53
+ interval = deserialize_duration(@schedule_options[:run_interval])
54
+
55
+ until next_time = next_future_time(times)
56
+ times.map!{ |time| time + interval }
57
+ end
58
+
59
+ # Update @schedule_options to avoid growing number of calculations each time
60
+ @schedule_options[:run_at] = times
61
+
62
+ next_time
63
+ end
64
+
65
+ private
66
+ # We don't want the run_interval to be serialized as a number of seconds.
67
+ # 1.day is not the same as 86400 (not all days are 86400 seconds long!)
68
+ def serialize_duration(duration)
69
+ case duration
70
+ when ActiveSupport::Duration
71
+ {value: duration.value, parts: duration.parts}
72
+ else
73
+ duration
74
+ end
75
+ end
76
+
77
+ def deserialize_duration(serialized)
78
+ case serialized
79
+ when Hash
80
+ ActiveSupport::Duration.new(serialized[:value], serialized[:parts])
81
+ else
82
+ serialized
83
+ end
84
+ end
85
+
86
+ def parse_time(time, timezone)
87
+ case time
88
+ when String
89
+ time_with_zone = get_timezone(timezone).parse(time)
90
+ parts = Date._parse(time, false)
91
+ wday = parts.fetch(:wday, time_with_zone.wday)
92
+ time_with_zone + (wday - time_with_zone.wday).days
93
+ else
94
+ time
95
+ end
96
+ end
97
+
98
+ def get_timezone(zone)
99
+ if zone
100
+ ActiveSupport::TimeZone.new(zone)
101
+ else
102
+ Time.zone
103
+ end
104
+ end
105
+
106
+ def next_future_time(times)
107
+ times.select{|time| time > Time.now}.min
108
+ end
109
+
110
+ module ClassMethods
111
+ def run_at(*times)
112
+ if times.length == 0
113
+ @run_at || run_every.from_now
114
+ else
115
+ if @run_at_inherited
116
+ @run_at = []
117
+ @run_at_inherited = nil
118
+ end
119
+ @run_at ||= []
120
+ @run_at.concat times
121
+ end
122
+ end
123
+
124
+ def run_every(interval = nil)
125
+ if interval.nil?
126
+ @run_interval || 1.hour
127
+ else
128
+ @run_interval = interval
129
+ end
130
+ end
131
+
132
+ def timezone(zone = nil)
133
+ if zone.nil?
134
+ @tz
135
+ else
136
+ @tz = zone
137
+ end
138
+ end
139
+
140
+ def priority(priority = nil)
141
+ if priority.nil?
142
+ @priority
143
+ else
144
+ @priority = priority
145
+ end
146
+ end
147
+
148
+ def queue(*args)
149
+ if args.length == 0
150
+ @queue
151
+ else
152
+ @queue = args.first
153
+ end
154
+ end
155
+
156
+ # Show all jobs for this schedule
157
+ def jobs(options = {})
158
+ options = options.with_indifferent_access
159
+ # Construct dynamic query with 'job_matching_param' if present
160
+ query = {'$or' => [{handler: /--- !ruby\/object:#{name}[\s+]/}, {handler: /--- !ruby\/object:#{name}$/}]}
161
+ if options[:job_matching_param].present?
162
+ matching_key = options[:job_matching_param]
163
+ matching_value = options[matching_key]
164
+ matching_yaml = yaml_quote(matching_value)
165
+ query = {'$and' => [query, handler: /#{matching_key}: #{matching_yaml}/]}
166
+ end
167
+
168
+ ::Delayed::Job.where(query)
169
+ end
170
+
171
+ # Remove all jobs for this schedule (Stop the schedule)
172
+ def unschedule(options = {})
173
+ jobs(options).each{|j| j.destroy}
174
+ end
175
+
176
+ # Main interface to start this schedule (adds it to the jobs table).
177
+ # Pass in a time to run the first job (nil runs the first job at run_interval from now).
178
+ def schedule(options = {})
179
+ schedule!(options) unless scheduled?(options)
180
+ end
181
+
182
+ def schedule!(options = {})
183
+ return unless Delayed::Worker.delay_jobs
184
+ unschedule(options)
185
+ new.schedule!(options)
186
+ end
187
+
188
+ def scheduled?(options = {})
189
+ jobs(options).count > 0
190
+ end
191
+
192
+ def inherited(subclass)
193
+ [:@run_at, :@run_interval, :@tz, :@priority].each do |var|
194
+ next unless instance_variable_defined? var
195
+ subclass.instance_variable_set var, self.instance_variable_get(var)
196
+ subclass.instance_variable_set "#{var}_inherited", true
197
+ end
198
+ end
199
+
200
+ private
201
+ def yaml_quote(value)
202
+ # In order to ensure matching indentation, place the element inside a
203
+ # two-level hash (the first level mimicking 'schedule_options', the second
204
+ # for #{job_matching_param}), and strip out the leading "---\n:a:\n :a: "
205
+ # but keep the trailing newline.
206
+ ({a: {a: value}}).to_yaml[14..-1]
207
+ end
208
+ end # ClassMethods
209
+ end # RecurringJob
210
+ end # Delayed
@@ -0,0 +1,3 @@
1
+ require 'delayed_job'
2
+ require 'delayed_job_mongoid'
3
+ require 'delayed/recurring_job'
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: delayed_job_recurring_mongoid_uriji
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.8
5
+ platform: ruby
6
+ authors:
7
+ - Tony Novak
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
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'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 3.6.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 3.6.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 3.6.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 3.6.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: database_cleaner
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.7.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.7.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: delayed_job
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '3.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: delayed_job_mongoid
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '2.0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '2.0'
139
+ description: Extends delayed_job_mongoid to support recurring jobs, including timezone
140
+ support
141
+ email: engineering@amitree.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - LICENSE
147
+ - README.md
148
+ - lib/delayed/recurring_job.rb
149
+ - lib/delayed_job_recurring_mongoid_uriji.rb
150
+ homepage: https://github.com/riverdrakar/delayed_job_recurring
151
+ licenses:
152
+ - MIT
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">"
161
+ - !ruby/object:Gem::Version
162
+ version: '1.9'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.6.14
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Recurring jobs for delayed_job_mongoid
174
+ test_files: []