sidekiq_simple_delay 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8828bf73cab33678a8f4f1e0d8a2c51328fa74fd252737e9789ee7447f238e1c
4
+ data.tar.gz: da61b4f204e3cfa49cec35d02689b9bc5fb19da5be5fcd67377508dc85945f80
5
+ SHA512:
6
+ metadata.gz: e08fd24c781ae84862392ded431873e98fd519190331bf003f74bffc5ce43c64a83c72f3eb584eb8ada3196b157d2e519de733e7384d696bdc87a66d1a53bcf6
7
+ data.tar.gz: e9f028312cbfc01d1f5d6219ac3ef6e8e09bf1936d042880da45142296306bbb385cc91a93dc53a014ac79350a00ef17c843ff391c8381c4432548a883e67a1e
@@ -0,0 +1,154 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+
7
+ spec_shared: &spec_shared
8
+ working_directory: ~/sidekiq_simple_delay
9
+ steps:
10
+ - checkout
11
+
12
+ - run:
13
+ name: install dependencies
14
+ command: |
15
+ bundle check --path vendor/bundle || bundle install --jobs=4 --retry=3 --path vendor/bundle
16
+
17
+ - run:
18
+ name: Make test-results
19
+ command: |
20
+ mkdir /tmp/test-results
21
+
22
+ - run:
23
+ name: Run basic specs
24
+ command: |
25
+ bundle exec rspec --format progress \
26
+ --format RspecJunitFormatter \
27
+ --out /tmp/test-results/rspec-basic.xml \
28
+ --format progress \
29
+ spec --tag ~enable_delay:true
30
+
31
+ - run:
32
+ name: Run enable_delay specs
33
+ command: |
34
+ bundle exec rspec --format progress \
35
+ --format RspecJunitFormatter \
36
+ --out /tmp/test-results/rspec-basic.xml \
37
+ --format progress \
38
+ spec --tag enable_delay:true
39
+
40
+ # collect reports
41
+ - store_test_results:
42
+ path: /tmp/test-results
43
+ - store_artifacts:
44
+ path: /tmp/test-results
45
+ destination: test-results
46
+
47
+ jobs:
48
+ deps:
49
+ docker:
50
+ - image: circleci/ruby:2.5
51
+ working_directory: ~/sidekiq_simple_delay
52
+
53
+ steps:
54
+ - checkout
55
+
56
+ # Download and cache dependencies
57
+ - restore_cache:
58
+ keys:
59
+ - v1-dependencies-{{ checksum "sidekiq_simple_delay.gemspec" }}
60
+
61
+ - run:
62
+ name: install dependencies
63
+ command: |
64
+ bundle check --path vendor/bundle || bundle install --jobs=4 --retry=3 --path vendor/bundle
65
+
66
+ - save_cache:
67
+ paths:
68
+ - vendor/bundle
69
+ key: v1-dependencies-{{ checksum "sidekiq_simple_delay.gemspec" }}
70
+
71
+ - run:
72
+ name: dependencies security audit
73
+ command: |
74
+ bundle exec bundle-audit check --update
75
+
76
+ - run:
77
+ name: Rubocop
78
+ command: bundle exec rubocop
79
+
80
+ ruby-2.5:
81
+ <<: *spec_shared
82
+ docker:
83
+ - image: circleci/ruby:2.5
84
+
85
+ ruby-2.4:
86
+ <<: *spec_shared
87
+ docker:
88
+ - image: circleci/ruby:2.4
89
+
90
+ ruby-2.3:
91
+ <<: *spec_shared
92
+ docker:
93
+ - image: circleci/ruby:2.3
94
+
95
+ ruby-2.2:
96
+ <<: *spec_shared
97
+ docker:
98
+ - image: circleci/ruby:2.2
99
+
100
+ generate_docs:
101
+ docker:
102
+ - image: circleci/ruby:2.5
103
+ working_directory: ~/sidekiq_simple_delay
104
+
105
+ steps:
106
+ - checkout
107
+
108
+ - restore_cache:
109
+ keys:
110
+ - v1-dependencies-{{ checksum "sidekiq_simple_delay.gemspec" }}
111
+
112
+ - run:
113
+ name: Setup bundler path
114
+ command: |
115
+ bundle check --path vendor/bundle
116
+
117
+ - run:
118
+ name: Generate Yard docs
119
+ command: |
120
+ bundle exec yard --output-dir /tmp/workspace/docs/yard
121
+
122
+ - run:
123
+ name: Num Docs
124
+ command: |
125
+ ls -al /tmp/workspace/docs/yard | wc -l
126
+
127
+ - persist_to_workspace:
128
+ root: /tmp/workspace/docs
129
+ paths:
130
+ - yard
131
+
132
+ workflows:
133
+ version: 2
134
+ build:
135
+ jobs:
136
+ - deps
137
+ - ruby-2.5:
138
+ requires:
139
+ - deps
140
+ - ruby-2.4:
141
+ requires:
142
+ - deps
143
+ - ruby-2.3:
144
+ requires:
145
+ - deps
146
+ - ruby-2.2:
147
+ requires:
148
+ - deps
149
+ - generate_docs:
150
+ requires:
151
+ - ruby-2.5
152
+ - ruby-2.4
153
+ - ruby-2.3
154
+ - ruby-2.2
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,25 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5.1
3
+
4
+ Metrics:
5
+ Enabled: false
6
+
7
+ Metrics/LineLength:
8
+ Max: 99
9
+ Exclude:
10
+ - "spec/**/*"
11
+ - "*.gemspec"
12
+
13
+ # to support Ruby 2.2
14
+ Style/NumericPredicate:
15
+ Enabled: false
16
+
17
+ # to support Ruby 2.2 & 2.3
18
+ Lint/UnifiedInteger:
19
+ Enabled: false
20
+
21
+ Style/MethodMissingSuper:
22
+ Enabled: false
23
+
24
+ Style/MissingRespondToMissing:
25
+ Enabled: false
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at les.fletcher@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in sidekiq_simple_delay.gemspec
8
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,99 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sidekiq_simple_delay (0.1.0)
5
+ sidekiq
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (5.2.1.1)
11
+ activesupport (= 5.2.1.1)
12
+ activerecord (5.2.1.1)
13
+ activemodel (= 5.2.1.1)
14
+ activesupport (= 5.2.1.1)
15
+ arel (>= 9.0)
16
+ activesupport (5.2.1.1)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 0.7, < 2)
19
+ minitest (~> 5.1)
20
+ tzinfo (~> 1.1)
21
+ arel (9.0.0)
22
+ ast (2.4.0)
23
+ bundler-audit (0.6.0)
24
+ bundler (~> 1.2)
25
+ thor (~> 0.18)
26
+ concurrent-ruby (1.1.3)
27
+ connection_pool (2.2.2)
28
+ diff-lcs (1.3)
29
+ fakeredis (0.7.0)
30
+ redis (>= 3.2, < 5.0)
31
+ i18n (1.1.1)
32
+ concurrent-ruby (~> 1.0)
33
+ jaro_winkler (1.5.1)
34
+ minitest (5.11.3)
35
+ parallel (1.12.1)
36
+ parser (2.5.3.0)
37
+ ast (~> 2.4.0)
38
+ powerpack (0.1.2)
39
+ rack (2.0.6)
40
+ rack-protection (2.0.4)
41
+ rack
42
+ rainbow (3.0.0)
43
+ rake (10.5.0)
44
+ redis (4.0.3)
45
+ rspec (3.8.0)
46
+ rspec-core (~> 3.8.0)
47
+ rspec-expectations (~> 3.8.0)
48
+ rspec-mocks (~> 3.8.0)
49
+ rspec-core (3.8.0)
50
+ rspec-support (~> 3.8.0)
51
+ rspec-expectations (3.8.2)
52
+ diff-lcs (>= 1.2.0, < 2.0)
53
+ rspec-support (~> 3.8.0)
54
+ rspec-mocks (3.8.0)
55
+ diff-lcs (>= 1.2.0, < 2.0)
56
+ rspec-support (~> 3.8.0)
57
+ rspec-support (3.8.0)
58
+ rspec_junit_formatter (0.4.1)
59
+ rspec-core (>= 2, < 4, != 2.12.0)
60
+ rubocop (0.60.0)
61
+ jaro_winkler (~> 1.5.1)
62
+ parallel (~> 1.10)
63
+ parser (>= 2.5, != 2.5.1.1)
64
+ powerpack (~> 0.1)
65
+ rainbow (>= 2.2.2, < 4.0)
66
+ ruby-progressbar (~> 1.7)
67
+ unicode-display_width (~> 1.4.0)
68
+ ruby-progressbar (1.10.0)
69
+ sidekiq (5.2.3)
70
+ connection_pool (~> 2.2, >= 2.2.2)
71
+ rack-protection (>= 1.5.0)
72
+ redis (>= 3.3.5, < 5)
73
+ sqlite3 (1.3.13)
74
+ thor (0.20.3)
75
+ thread_safe (0.3.6)
76
+ tzinfo (1.2.5)
77
+ thread_safe (~> 0.1)
78
+ unicode-display_width (1.4.0)
79
+ yard (0.9.16)
80
+
81
+ PLATFORMS
82
+ ruby
83
+
84
+ DEPENDENCIES
85
+ activerecord (> 3.0)
86
+ activesupport (> 3.0)
87
+ bundler (~> 1.16)
88
+ bundler-audit
89
+ fakeredis
90
+ rake (~> 10.0)
91
+ rspec (~> 3.0)
92
+ rspec_junit_formatter (~> 0.2)
93
+ rubocop (= 0.60.0)
94
+ sidekiq_simple_delay!
95
+ sqlite3
96
+ yard
97
+
98
+ BUNDLED WITH
99
+ 1.17.1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Les Fletcher
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # SidekiqSimpleDelay
2
+
3
+ Adds Sidekiq [Delay](https://github.com/mperham/sidekiq/wiki/Delayed-extensions) functionality, but adds some restrictions to prevent object marshalling.
4
+
5
+ Sidekiq's built-in delay feature only allows you to turn the functionality for all classes and only for class methods. `SidekiqSimpleDelay` allows you to specify classes you want to enable the delay methods for. In addition to class methods, since we are now checking and restricting the arguments to be simple JSON convertable objects, we can add this delay functionality to instances of classes.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'sidekiq_simple_delay'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install sidekiq_simple_delay
22
+
23
+ ## Usage
24
+
25
+ You can find the docs on [rubdoc.info](https://www.rubydoc.info/github/Latermedia/sidekiq_simple_delay/master).
26
+
27
+ ### All Classes
28
+
29
+ To add delay functionality all classes. This is similar to `Sidekiq::Extensions.enable_delay!`.
30
+
31
+ ```ruby
32
+ SidekiqSimpleDelay.enable_delay!
33
+
34
+ MyClass.simple_delay.some_method(:arg)
35
+ ```
36
+
37
+ ### Single Class
38
+
39
+ We can also add the functionality to a single class:
40
+ ```ruby
41
+ class User
42
+ extend SidekiqSimpleDelay::DelayMethods
43
+
44
+ def self.greeting
45
+ 'Hello Everyone'
46
+ end
47
+ end
48
+
49
+ # ...
50
+
51
+ User.simple_delay.greeting
52
+ ```
53
+
54
+ To add delay functionality to the instances of a class:
55
+ ```ruby
56
+ class User
57
+ include SidekiqSimpleDelay::DelayMethods
58
+
59
+ def greeting(name)
60
+ "Hello, #{name}"
61
+ end
62
+ end
63
+
64
+ # ...
65
+
66
+ User.new.simple_delay.greeting('Les')
67
+ ```
68
+
69
+ ### Simple Delay Methods
70
+
71
+ Three methods are provided that map to the three main invocations for Sidekiq.
72
+ * `simple_delay` -> `perform_async`
73
+ * `simple_delay_for` -> `perform_in`
74
+ * `simple_delay_until` -> `perform_at`
75
+
76
+ ### Devops
77
+
78
+ A few conveniences are provided that allow you enable this functionality from the command line.
79
+
80
+ Let's say we have a class the contains a long running method that we want to push to the background. In the past we'd have to make a one time worker to run this job. Now we can create the job directly from our console without modifying the class's code.
81
+
82
+ ```ruby
83
+ class Task
84
+ def self.long_running_task(task_arg1, task_arg2)
85
+ # things that take a long time...
86
+ end
87
+ end
88
+ ```
89
+
90
+ From the console:
91
+ ```ruby
92
+ SidekiqSimpleDelay.enable_delay_class!(Task)
93
+
94
+ Task.simple_delay.long_running_task('things', 1234)
95
+ ```
96
+
97
+ The great thing is, assuming you have added `sidekiq_simple_delay` to your `Gemfile`, this will just work™. The job that is enqueued doesn't need `Task` to know anything about Sidekiq, workers, or jobs.
98
+
99
+ Similar to `enable_delay_class!` there is also `enable_delay_instance!` to do the same thing for instances and instance methods of `Task`.
100
+
101
+ ```ruby
102
+ SidekiqSimpleDelay.enable_delay_instance!(Task)
103
+
104
+ Task.new.simple_delay.long_running_tasks_instance_method
105
+ ```
106
+
107
+ ### Delaying Instances
108
+
109
+ Delaying class methods is pretty simple and straight forward. There is no state to keep track of, so we just pass the class, the method name and whatever arguments we need. In order to be able to delay methods on an instance we have to do some book keeping and add some limitations.
110
+
111
+ `Klass` can delay method invocation on it's instances if:
112
+ * `Klass.new` takes no arguments
113
+ or
114
+ * `Klass` implements the public instance method `initialize_args` which returns an array of arguments to be used to initialize an instance of `Klass` in the `SimpleDelayedWorker`
115
+
116
+ To implement custom instantiation within the `SimpleDelayedWorker`, `Klass` can implement the `simple_delay_initialize` public class method that takes the same arguments `initialize_args` returns.
117
+
118
+ One use case of these methods would be for delaying methods on an `ActiveRecord` objects.
119
+
120
+ ```ruby
121
+ class ApplicationRecord < ActiveRecord::Base
122
+ def initialize_args
123
+ [id]
124
+ end
125
+
126
+ def self.simple_delay_initialize(*args)
127
+ find(args[0])
128
+ end
129
+ end
130
+
131
+ class User < ApplicationRecord
132
+ def long_running_user_task(arg1)
133
+ # takes a long time
134
+ end
135
+ end
136
+ ```
137
+
138
+ From the console:
139
+ ```ruby
140
+ SidekiqSimpleDelay.enable_delay_instance!(User)
141
+
142
+ User.where(column1: true).find_each do |user|
143
+ user.simple_delay.long_running_user_task('things')
144
+ end
145
+ ```
146
+
147
+ ### Simple Objects
148
+
149
+ `SidekiqSimpleDelay` only allows simple objects to be used as parameters to the delayed method. These objects are:
150
+
151
+ * `NilClass`
152
+ * `TrueClass`
153
+ * `FalseClass`
154
+ * `String`
155
+ * `Symbol`
156
+ * `Hash`
157
+ * `Array`
158
+ * `Float`
159
+ * `Integer` (`RUBY_VERSION` >= 2.4.0)
160
+ * `Fixnum` (`RUBY_VERSION` < 2.4.0)
161
+ * `Bignum` (`RUBY_VERSION` < 2.4.0)
162
+
163
+ `SidekiqSimpleDelay::Utils.simple_object?` will do a depth first recursive check to make sure nothing but the above makes it into the arguments.
164
+
165
+ In addition requiring arguments being simple, a requirement of no keyword or block arguments is imposed. There is a chance the keyword argument restriction could be lifted, but this would take a fair bit of work in `SimpleDelayedWorker` to get working correctly. For now the restriction is there to keep one from shooting themselves in the foot.
166
+
167
+ ## Development
168
+
169
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
170
+
171
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
172
+
173
+ ## Tests
174
+
175
+ Since parts of the functionality is optional and modifies other classes and objects, the specs aren't meant to be run all at the same time. This is to isolate the environment the tests are executing in.
176
+
177
+ To run the tests:
178
+
179
+ ```bash
180
+ ./run_specs
181
+ ```
182
+
183
+ Tests are currently run against the following Ruby version:
184
+ - 2.5
185
+ - 2.4
186
+ - 2.3
187
+ - 2.2
188
+
189
+ ## Contributing
190
+
191
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Latermedia/sidekiq_simple_delay. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
192
+
193
+ ## License
194
+
195
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
196
+
197
+ ## Code of Conduct
198
+
199
+ Everyone interacting in the SidekiqSimpleDelay project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/Latermedia/sidekiq_simple_delay/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'sidekiq_simple_delay'
6
+ require 'sidekiq_simple_delay/delay_methods'
7
+
8
+ # You can add fixtures and/or initialization code here to make experimenting
9
+ # with your gem easier. You can also use a different console, if you like.
10
+
11
+ # (If you use this, don't forget to add pry to your Gemfile!)
12
+ # require "pry"
13
+ # Pry.start
14
+
15
+ require 'irb'
16
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sidekiq_simple_delay/delay_worker'
4
+ require 'sidekiq_simple_delay/generic_proxy'
5
+
6
+ module SidekiqSimpleDelay
7
+ # Aliased class methods to be added to Class
8
+ module DelayMethods
9
+ def simple_sidekiq_delay(options = {})
10
+ Proxy.new(SimpleDelayedWorker, self, options)
11
+ end
12
+
13
+ def simple_sidekiq_delay_for(interval, options = {})
14
+ Proxy.new(SimpleDelayedWorker, self, options.merge('at' => Time.now.to_f + interval.to_f))
15
+ end
16
+
17
+ def simple_sidekiq_delay_until(timestamp, options = {})
18
+ Proxy.new(SimpleDelayedWorker, self, options.merge('at' => timestamp.to_f))
19
+ end
20
+
21
+ alias simple_delay simple_sidekiq_delay
22
+ alias simple_delay_for simple_sidekiq_delay_for
23
+ alias simple_delay_until simple_sidekiq_delay_until
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sidekiq'
4
+ require 'sidekiq_simple_delay/generic_proxy'
5
+
6
+ module SidekiqSimpleDelay
7
+ # Worker that handles the delayed functionality
8
+ class SimpleDelayedWorker
9
+ include Sidekiq::Worker
10
+
11
+ def perform(args)
12
+ target_klass = Object.const_get(args.fetch('target_klass'))
13
+
14
+ target =
15
+ if args.key?('init_args')
16
+ if target_klass.respond_to?(:simple_delay_initialize)
17
+ target_klass.simple_delay_initialize(*args['init_args'])
18
+ else
19
+ target_klass.new(*args['init_args'])
20
+ end
21
+ else
22
+ target_klass
23
+ end
24
+
25
+ method_name = args['m']
26
+ method_args = args['args']
27
+
28
+ target.__send__(method_name, *method_args)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sidekiq_simple_delay/utils'
4
+
5
+ module SidekiqSimpleDelay
6
+ # Simple proxy object that handles enqueuing delay workers via `method_missing`
7
+ class Proxy < Object
8
+ def initialize(performable, target, options = {})
9
+ @performable = performable
10
+ @target = target
11
+ @opts = options
12
+ end
13
+
14
+ def method_missing(name, *args)
15
+ worker_args = {
16
+ 'm' => name,
17
+ 'args' => args
18
+ }
19
+
20
+ # check to make sure there are no keyword or block args
21
+ method_args_sig = @target.method(name).parameters
22
+
23
+ num_req_key_args = method_args_sig.count { |p| p[0] == :keyreq }
24
+ num_opt_key_args = method_args_sig.count { |p| p[0] == :key }
25
+ num_var_key_args = method_args_sig.count { |p| p[0] == :keyrest }
26
+
27
+ uses_keyword_args = num_req_key_args > 0 || num_opt_key_args > 0 || num_var_key_args > 0
28
+ raise ArgumentError, 'Cannot delay methods with named arguments' if uses_keyword_args
29
+
30
+ num_block_args = method_args_sig.select { |p| p[0] == :block }.length
31
+ raise ArgumentError, 'Cannot delay methods with named block argument' if num_block_args > 0
32
+
33
+ # Calling class methods is always permitted
34
+ if @target.is_a?(Class)
35
+ worker_args['target_klass'] = @target.name
36
+ # If this is an instance, it has to tell us what args we would use
37
+ # to reinitialize it in the worker. If `#new` takes no args, that is also ok
38
+ elsif @target.respond_to?(:initialize_args) || @target.method(:initialize).arity == 0
39
+ worker_args['target_klass'] = @target.class.name
40
+ # Verify it works with arrays, hashes, named arguments, and lists of arguments
41
+ # These args will be passed to `simple_delay_initialize` if defined
42
+ # or new otherwise
43
+ worker_args['init_args'] =
44
+ if @target.respond_to?(:initialize_args)
45
+ @target.initialize_args
46
+ else
47
+ []
48
+ end
49
+ else
50
+ # This is an instance of a class that is not simple delay compatible
51
+ raise ArgumentError, "Objects of class #{@target.class} must implement " \
52
+ '#initialize_args or be calling a method with an arity of 0 to be delayed'
53
+ end
54
+
55
+ # the args have to be simple and convertable to JSON
56
+ raise ArgumentError, 'args are not serializable, cannot use simple_delay' unless Utils.simple_object?(worker_args)
57
+
58
+ @performable.client_push({ 'class' => @performable, 'args' => [worker_args] }.merge(@opts))
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module SidekiqSimpleDelay
6
+ # utility methods
7
+ class Utils
8
+ class << self
9
+ SYSTEM_SIMPLE_CLASSES = Set.new(
10
+ [
11
+ NilClass,
12
+ TrueClass,
13
+ FalseClass,
14
+ String,
15
+ Symbol
16
+ ]
17
+ ).freeze
18
+
19
+ SYSTEM_SIMPLE_COMPLEX_CLASSES = Set.new(
20
+ [
21
+ Hash,
22
+ Array
23
+ ]
24
+ ).freeze
25
+
26
+ SYSTEM_SIMPLE_NUMERIC_CLASSES =
27
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.4.0')
28
+ Set.new([Integer, Float]).freeze
29
+ else
30
+ Set.new([Fixnum, Bignum, Float]).freeze
31
+ end
32
+
33
+ def simple_object?(obj)
34
+ klass = obj.class
35
+
36
+ if SYSTEM_SIMPLE_COMPLEX_CLASSES.include?(klass)
37
+ obj.all? { |o| simple_object?(o) }
38
+ elsif SYSTEM_SIMPLE_CLASSES.include?(klass)
39
+ true
40
+ elsif SYSTEM_SIMPLE_NUMERIC_CLASSES.include?(klass)
41
+ true
42
+ else
43
+ false
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqSimpleDelay
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sidekiq_simple_delay/version'
4
+ require 'sidekiq_simple_delay/delay_methods'
5
+
6
+ # Sidekiq delay functionality with some restrictions
7
+ module SidekiqSimpleDelay
8
+ class << self
9
+ # Adds simple_delay class methods to all classes
10
+ def enable_delay!
11
+ enable_delay_instance!(Module)
12
+ end
13
+
14
+ # Adds simple_delay class methods to klass
15
+ def enable_delay_class!(klass)
16
+ raise ArgumentError, 'klass must be a Class' unless klass.class.is_a?(Class)
17
+
18
+ klass.__send__(:extend, SidekiqSimpleDelay::DelayMethods)
19
+ end
20
+
21
+ # Adds simple_delay instance methods to klass
22
+ def enable_delay_instance!(klass)
23
+ raise ArgumentError, 'klass must be a Class' unless klass.class.is_a?(Class)
24
+
25
+ klass.__send__(:include, SidekiqSimpleDelay::DelayMethods)
26
+ end
27
+ end
28
+ end
data/run_specs ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundle exec rspec spec --tag ~enable_delay:true
4
+ bundle exec rspec spec --tag enable_delay:true
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'sidekiq_simple_delay/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'sidekiq_simple_delay'
9
+ spec.version = SidekiqSimpleDelay::VERSION
10
+ spec.authors = ['Les Fletcher']
11
+ spec.email = ['les@later.com']
12
+
13
+ spec.summary = "Restricts Sidekiq delay workers to only accept 'simple' arguments."
14
+ # spec.description = %q{TODO: Write a longer description or delete this line.}
15
+ spec.homepage = 'https://github.com/Latermedia/sidekiq_simple_delay'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_dependency('sidekiq')
26
+
27
+ spec.add_development_dependency 'activerecord', '> 3.0'
28
+ spec.add_development_dependency 'activesupport', '> 3.0'
29
+ spec.add_development_dependency 'bundler', '~> 1.16'
30
+ spec.add_development_dependency 'bundler-audit'
31
+ spec.add_development_dependency 'fakeredis'
32
+ spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rspec', '~> 3.0'
34
+ spec.add_development_dependency 'rspec_junit_formatter', '~> 0.2'
35
+ spec.add_development_dependency 'rubocop', '0.60.0'
36
+ spec.add_development_dependency 'sqlite3'
37
+ spec.add_development_dependency 'yard'
38
+ end
metadata ADDED
@@ -0,0 +1,232 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq_simple_delay
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Les Fletcher
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-12-01 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: '0'
20
+ type: :runtime
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: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.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.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.16'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.16'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler-audit
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fakeredis
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :development
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: rspec_junit_formatter
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.2'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.2'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '='
144
+ - !ruby/object:Gem::Version
145
+ version: 0.60.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '='
151
+ - !ruby/object:Gem::Version
152
+ version: 0.60.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: sqlite3
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: yard
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description:
182
+ email:
183
+ - les@later.com
184
+ executables: []
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - ".circleci/config.yml"
189
+ - ".gitignore"
190
+ - ".rspec"
191
+ - ".rubocop.yml"
192
+ - CODE_OF_CONDUCT.md
193
+ - Gemfile
194
+ - Gemfile.lock
195
+ - LICENSE.txt
196
+ - README.md
197
+ - Rakefile
198
+ - bin/console
199
+ - bin/setup
200
+ - lib/sidekiq_simple_delay.rb
201
+ - lib/sidekiq_simple_delay/delay_methods.rb
202
+ - lib/sidekiq_simple_delay/delay_worker.rb
203
+ - lib/sidekiq_simple_delay/generic_proxy.rb
204
+ - lib/sidekiq_simple_delay/utils.rb
205
+ - lib/sidekiq_simple_delay/version.rb
206
+ - run_specs
207
+ - sidekiq_simple_delay.gemspec
208
+ homepage: https://github.com/Latermedia/sidekiq_simple_delay
209
+ licenses:
210
+ - MIT
211
+ metadata: {}
212
+ post_install_message:
213
+ rdoc_options: []
214
+ require_paths:
215
+ - lib
216
+ required_ruby_version: !ruby/object:Gem::Requirement
217
+ requirements:
218
+ - - ">="
219
+ - !ruby/object:Gem::Version
220
+ version: '0'
221
+ required_rubygems_version: !ruby/object:Gem::Requirement
222
+ requirements:
223
+ - - ">="
224
+ - !ruby/object:Gem::Version
225
+ version: '0'
226
+ requirements: []
227
+ rubyforge_project:
228
+ rubygems_version: 2.7.6
229
+ signing_key:
230
+ specification_version: 4
231
+ summary: Restricts Sidekiq delay workers to only accept 'simple' arguments.
232
+ test_files: []