sidekiq-repeat 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 640363fb32bb0a5e6c6d7b9ce47109bb4d26244e
4
+ data.tar.gz: 43481093dd233b479c4fa4c5809cee3b547911d2
5
+ SHA512:
6
+ metadata.gz: 2957cc62da166c65fc5ea481a39a903d6a6e2a533aa3f4b0a81171a0975b9d0ce253b995bdd3d9a61b4e729d4d7cb1252c515346750840e04c66955af3eed0b5
7
+ data.tar.gz: cb43747010d8c0aa4243a4d8d161270d54d4b2e19a75acb2dd9f446415157d70047bfa889a3e5ff61187abd7be7905019bf8e50abc88bb5cc7be36ab17e2727c
@@ -0,0 +1,11 @@
1
+ module Sidekiq
2
+ module Repeat
3
+ class Middleware
4
+ def call(worker, item, queue)
5
+ yield
6
+ ensure
7
+ worker.class.reschedule if worker.class.respond_to?(:reschedule)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,96 @@
1
+ module Sidekiq
2
+ module Repeat
3
+ ##
4
+ # This is a mini compatibility layer for the ice_cube syntax. Nothing fancy.
5
+ # It only supports interval-based -ly functions like "hourly(4)" and array
6
+ # list information like .minute_of_hour(0,15,30,45), as these are the ones
7
+ # that we use.
8
+ module MiniIceCube
9
+ module IceCubeDslErrorHandling
10
+ IceCubeSyntaxError = Class.new(StandardError)
11
+
12
+ def unsupported(msg)
13
+ fail IceCubeSyntaxError, "Sidekiq::Repeat: Unsupported ice_cube syntax. Please refer to the documentation. (#{msg})"
14
+ end
15
+
16
+ def method_missing(meth, *args, &block)
17
+ unsupported("method not found: #{meth}")
18
+ end
19
+ end
20
+
21
+ class CronSyntax
22
+ include IceCubeDslErrorHandling
23
+
24
+ class << self
25
+ def define_items_method(name, slot)
26
+ define_method(name) do |*args|
27
+ unsupported("invalid arguments for #{name}") unless args.any? && args.all? { |i| i.is_a?(Integer) || i =~ /\d+/ }
28
+ @slots[slot] = args.map(&:to_s).join(',')
29
+ self
30
+ end
31
+ end
32
+ end
33
+
34
+ def initialize(*args)
35
+ @slots = args
36
+ end
37
+
38
+ def to_s
39
+ @slots.map(&:to_s).join(' ')
40
+ end
41
+
42
+ define_items_method(:minute_of_hour, 0)
43
+ define_items_method(:hour_of_day, 1)
44
+ define_items_method(:day_of_month, 2)
45
+ end
46
+
47
+ class MainDsl
48
+ include IceCubeDslErrorHandling
49
+
50
+ class << self
51
+ def define_interval_method(name, base, *stars_prefix)
52
+ define_method(name) do |*args|
53
+ stars = stars_prefix.dup || []
54
+
55
+ if args.any?
56
+ interval = args.first.to_i
57
+ unsupported("invalid interval: #{interval}") unless interval && interval >= 0 && interval <= base
58
+
59
+ # Instead of always calculating the next() occurrence as ice_cube does,
60
+ # we can only have fixed run times (as per cron syntax). Hence we calculate
61
+ # the run times based on integer division of interval and time frame, using
62
+ # a random start offset based on the remaining time.
63
+ #
64
+ # NOTE: This effectivly means that after the last run in the time frame the
65
+ # next run will be scheduled after interval+remainder.
66
+ #
67
+ # Example: minutely(17) will run 3 times per hour. After the last run each
68
+ # hour the skip will be 17 + 9 = 26 minutes. A random offset in
69
+ # [0,26) will be applied, so a possible cron line could be '4,21,38'.
70
+
71
+ times = []
72
+ nruns = (base / interval).floor
73
+ rnoff = rand(interval + base % interval).floor
74
+ runs = nruns.times.map { |i| i * interval + rnoff }
75
+ stars << runs.map(&:to_s).join(',')
76
+ end
77
+
78
+ stars.fill('*', stars.size..4)
79
+ CronSyntax.new(*stars)
80
+ end
81
+ end
82
+ end
83
+
84
+ def weekly(*args)
85
+ unsupported('interval argument unsupported for weekly') unless args.empty?
86
+ CronSyntax.new(0, 3, '*', '*', 0) # Sundays at 3AM.
87
+ end
88
+
89
+ define_interval_method(:minutely, 60)
90
+ define_interval_method(:hourly, 24, 0) # At first minute of hour.
91
+ define_interval_method(:daily, 31, 0, 3) # At night, 3AM.
92
+ define_interval_method(:monthly, 12, 0, 3, 0) # First day of the month, 3AM.
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,47 @@
1
+ module Sidekiq
2
+ module Repeat
3
+ module Repeatable
4
+ module ClassMethods
5
+ def repeat(&block)
6
+ @cronline = MiniIceCube::MainDsl.new.instance_eval(&block).to_s
7
+ @cronline = CronParser.new(@cronline)
8
+ rescue ArgumentError
9
+ fail "repeat '#{@cronline}' in class #{self.name} is not a valid cron line"
10
+ end
11
+
12
+ def reschedule
13
+ return unless repeat_configured?
14
+ return if already_scheduled?
15
+
16
+ ts = @cronline.next
17
+ self.perform_at ts.to_f
18
+ Sidekiq.logger.info "Scheduled #{self.name} for #{ts}."
19
+ end
20
+
21
+ def repeat_configured?
22
+ !!@cronline
23
+ end
24
+
25
+ def already_scheduled?
26
+ @ss ||= Sidekiq::ScheduledSet.new
27
+ @ss.any? { |job| job.klass == self.name }
28
+ end
29
+ end
30
+
31
+ class << self
32
+ def repeatables
33
+ @repeatables ||= []
34
+ end
35
+
36
+ def reschedule_all
37
+ repeatables.each(&:reschedule)
38
+ end
39
+
40
+ def included(klass)
41
+ klass.extend(Sidekiq::Repeat::Repeatable::ClassMethods)
42
+ repeatables << klass
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,5 @@
1
+ module Sidekiq
2
+ module Repeat
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require 'parse-cron'
2
+ require 'sidekiq'
3
+ require 'sidekiq/api'
4
+
5
+ require 'sidekiq/repeat/middleware'
6
+ require 'sidekiq/repeat/mini_ice_cube'
7
+ require 'sidekiq/repeat/repeatable'
8
+ require 'sidekiq/repeat/version'
@@ -0,0 +1,11 @@
1
+ require 'sidekiq/repeat'
2
+
3
+ Sidekiq.configure_server do |config|
4
+ config.server_middleware do |chain|
5
+ chain.add Sidekiq::Repeat::Middleware
6
+ end
7
+
8
+ config.on(:startup) do
9
+ Sidekiq::Repeat::Repeatable.reschedule_all
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq-repeat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - FlavourSys Technology GmbH
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sidekiq
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: parse-cron
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.4'
69
+ description: This gem adds recurring jobs to Sidekiq. It is heavily inspired by the
70
+ sidekiq-dejavu and sidetiq gems.
71
+ email: technology@flavoursys.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/sidekiq-repeat.rb
77
+ - lib/sidekiq/repeat.rb
78
+ - lib/sidekiq/repeat/middleware.rb
79
+ - lib/sidekiq/repeat/mini_ice_cube.rb
80
+ - lib/sidekiq/repeat/repeatable.rb
81
+ - lib/sidekiq/repeat/version.rb
82
+ homepage: https://github.com/FlavourSys/sidekiq-repeat
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.2.2
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Repeat is a clockless recurring job system for Sidekiq.
106
+ test_files: []