cloudtasker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +27 -0
  5. data/.travis.yml +7 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +247 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +43 -0
  11. data/Rakefile +8 -0
  12. data/app/controllers/cloudtasker/application_controller.rb +6 -0
  13. data/app/controllers/cloudtasker/worker_controller.rb +38 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/cloudtasker.gemspec +48 -0
  17. data/config/routes.rb +5 -0
  18. data/lib/cloudtasker.rb +31 -0
  19. data/lib/cloudtasker/authentication_error.rb +6 -0
  20. data/lib/cloudtasker/authenticator.rb +55 -0
  21. data/lib/cloudtasker/batch.rb +5 -0
  22. data/lib/cloudtasker/batch/batch_progress.rb +97 -0
  23. data/lib/cloudtasker/batch/config.rb +11 -0
  24. data/lib/cloudtasker/batch/extension/worker.rb +13 -0
  25. data/lib/cloudtasker/batch/job.rb +320 -0
  26. data/lib/cloudtasker/batch/middleware.rb +24 -0
  27. data/lib/cloudtasker/batch/middleware/server.rb +14 -0
  28. data/lib/cloudtasker/config.rb +122 -0
  29. data/lib/cloudtasker/cron.rb +5 -0
  30. data/lib/cloudtasker/cron/config.rb +11 -0
  31. data/lib/cloudtasker/cron/job.rb +207 -0
  32. data/lib/cloudtasker/cron/middleware.rb +21 -0
  33. data/lib/cloudtasker/cron/middleware/server.rb +14 -0
  34. data/lib/cloudtasker/cron/schedule.rb +227 -0
  35. data/lib/cloudtasker/engine.rb +20 -0
  36. data/lib/cloudtasker/invalid_worker_error.rb +6 -0
  37. data/lib/cloudtasker/meta_store.rb +86 -0
  38. data/lib/cloudtasker/middleware/chain.rb +250 -0
  39. data/lib/cloudtasker/redis_client.rb +115 -0
  40. data/lib/cloudtasker/task.rb +175 -0
  41. data/lib/cloudtasker/unique_job.rb +5 -0
  42. data/lib/cloudtasker/unique_job/config.rb +10 -0
  43. data/lib/cloudtasker/unique_job/conflict_strategy/base_strategy.rb +37 -0
  44. data/lib/cloudtasker/unique_job/conflict_strategy/raise.rb +28 -0
  45. data/lib/cloudtasker/unique_job/conflict_strategy/reject.rb +11 -0
  46. data/lib/cloudtasker/unique_job/conflict_strategy/reschedule.rb +30 -0
  47. data/lib/cloudtasker/unique_job/job.rb +136 -0
  48. data/lib/cloudtasker/unique_job/lock/base_lock.rb +70 -0
  49. data/lib/cloudtasker/unique_job/lock/no_op.rb +11 -0
  50. data/lib/cloudtasker/unique_job/lock/until_executed.rb +34 -0
  51. data/lib/cloudtasker/unique_job/lock/until_executing.rb +30 -0
  52. data/lib/cloudtasker/unique_job/lock/while_executing.rb +23 -0
  53. data/lib/cloudtasker/unique_job/lock_error.rb +8 -0
  54. data/lib/cloudtasker/unique_job/middleware.rb +36 -0
  55. data/lib/cloudtasker/unique_job/middleware/client.rb +14 -0
  56. data/lib/cloudtasker/unique_job/middleware/server.rb +14 -0
  57. data/lib/cloudtasker/version.rb +5 -0
  58. data/lib/cloudtasker/worker.rb +211 -0
  59. metadata +286 -0
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ module UniqueJob
5
+ module Lock
6
+ # Equivalent to no lock
7
+ class NoOp < BaseLock
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ module UniqueJob
5
+ module Lock
6
+ # Conflict if any other job with the same args is scheduled or moved to execution
7
+ # while the first job is pending or executing.
8
+ class UntilExecuted < BaseLock
9
+ #
10
+ # Acquire a lock for the job and trigger a conflict
11
+ # if the lock could not be acquired.
12
+ #
13
+ def schedule
14
+ job.lock!
15
+ yield
16
+ rescue LockError
17
+ conflict_instance.on_schedule { yield }
18
+ end
19
+
20
+ #
21
+ # Acquire a lock for the job and trigger a conflict
22
+ # if the lock could not be acquired.
23
+ #
24
+ def execute
25
+ job.lock!
26
+ yield
27
+ job.unlock!
28
+ rescue LockError
29
+ conflict_instance.on_execute { yield }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ module UniqueJob
5
+ module Lock
6
+ # Conflict if any other job with the same args is scheduled
7
+ # while the first job is pending.
8
+ class UntilExecuting < BaseLock
9
+ #
10
+ # Acquire a lock for the job and trigger a conflict
11
+ # if the lock could not be acquired.
12
+ #
13
+ def schedule
14
+ job.lock!
15
+ yield
16
+ rescue LockError
17
+ conflict_instance.on_schedule { yield }
18
+ end
19
+
20
+ #
21
+ # Release the lock and perform the job.
22
+ #
23
+ def execute
24
+ job.unlock!
25
+ yield
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ module UniqueJob
5
+ module Lock
6
+ # Conflict if any other job with the same args is moved to execution
7
+ # while the first job is executing.
8
+ class WhileExecuting < BaseLock
9
+ #
10
+ # Acquire a lock for the job and trigger a conflict
11
+ # if the lock could not be acquired.
12
+ #
13
+ def execute
14
+ job.lock!
15
+ yield
16
+ job.unlock!
17
+ rescue LockError
18
+ conflict_instance.on_execute { yield }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ module UniqueJob
5
+ class LockError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cloudtasker/redis_client'
4
+
5
+ require_relative 'lock_error'
6
+ require_relative 'config'
7
+
8
+ require_relative 'conflict_strategy/base_strategy'
9
+ require_relative 'conflict_strategy/raise'
10
+ require_relative 'conflict_strategy/reject'
11
+ require_relative 'conflict_strategy/reschedule'
12
+
13
+ require_relative 'lock/base_lock'
14
+ require_relative 'lock/no_op'
15
+ require_relative 'lock/until_executed'
16
+ require_relative 'lock/until_executing'
17
+ require_relative 'lock/while_executing'
18
+
19
+ require_relative 'job'
20
+
21
+ require_relative 'middleware/client'
22
+ require_relative 'middleware/server'
23
+
24
+ module Cloudtasker
25
+ module UniqueJob
26
+ # Registration module
27
+ module Middleware
28
+ def self.configure
29
+ Cloudtasker.configure do |config|
30
+ config.client_middleware { |c| c.add(Middleware::Client) }
31
+ config.server_middleware { |c| c.add(Middleware::Server) }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ module UniqueJob
5
+ module Middleware
6
+ # Client middleware, invoked when jobs are scheduled
7
+ class Client
8
+ def call(worker)
9
+ Job.new(worker).lock_instance.schedule { yield }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ module UniqueJob
5
+ module Middleware
6
+ # Server middleware, invoked when jobs are executed
7
+ class Server
8
+ def call(worker)
9
+ Job.new(worker).lock_instance.execute { yield }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ # Cloud Task based workers
5
+ module Worker
6
+ # Add class method to including class
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ base.attr_accessor :job_args, :job_id, :job_meta, :job_reenqueued
10
+ end
11
+
12
+ #
13
+ # Return a worker instance from a serialized worker.
14
+ # A worker can be serialized by calling `MyWorker#to_json`
15
+ #
16
+ # @param [String] json Worker serialized as json.
17
+ #
18
+ # @return [Cloudtasker::Worker, nil] The instantiated worker.
19
+ #
20
+ def self.from_json(json)
21
+ from_hash(JSON.parse(json))
22
+ rescue JSON::ParserError
23
+ nil
24
+ end
25
+
26
+ #
27
+ # Return a worker instance from a worker hash description.
28
+ # A worker hash description is typically generated by calling `MyWorker#to_h`
29
+ #
30
+ # @param [Hash] hash A worker hash description.
31
+ #
32
+ # @return [Cloudtasker::Worker, nil] The instantiated worker.
33
+ #
34
+ def self.from_hash(hash)
35
+ # Symbolize payload keys
36
+ payload = JSON.parse(hash.to_json, symbolize_names: true)
37
+
38
+ # Extract worker parameters
39
+ klass_name = payload&.dig(:worker)
40
+ return nil unless klass_name
41
+
42
+ # Check that worker class is a valid worker
43
+ worker_klass = Object.const_get(klass_name)
44
+ return nil unless worker_klass.include?(self)
45
+
46
+ # Return instantiated worker
47
+ worker_klass.new(payload.slice(:job_args, :job_id, :job_meta))
48
+ rescue NameError
49
+ nil
50
+ end
51
+
52
+ # Module class methods
53
+ module ClassMethods
54
+ #
55
+ # Set the worker runtime options.
56
+ #
57
+ # @param [Hash] opts The worker options
58
+ #
59
+ # @return [<Type>] <description>
60
+ #
61
+ def cloudtasker_options(opts = {})
62
+ opt_list = opts&.map { |k, v| [k.to_s, v] } || [] # stringify
63
+ @cloudtasker_options_hash = Hash[opt_list]
64
+ end
65
+
66
+ #
67
+ # Return the worker runtime options.
68
+ #
69
+ # @return [Hash] The worker runtime options.
70
+ #
71
+ def cloudtasker_options_hash
72
+ @cloudtasker_options_hash
73
+ end
74
+
75
+ #
76
+ # Enqueue worker in the backgroundf.
77
+ #
78
+ # @param [Array<any>] *args List of worker arguments
79
+ #
80
+ # @return [Google::Cloud::Tasks::V2beta3::Task] The Google Task response
81
+ #
82
+ def perform_async(*args)
83
+ perform_in(nil, *args)
84
+ end
85
+
86
+ #
87
+ # Enqueue worker and delay processing.
88
+ #
89
+ # @param [Integer, nil] interval The delay in seconds.
90
+ # @param [Array<any>] *args List of worker arguments.
91
+ #
92
+ # @return [Google::Cloud::Tasks::V2beta3::Task] The Google Task response
93
+ #
94
+ def perform_in(interval, *args)
95
+ new(job_args: args).schedule(interval: interval)
96
+ end
97
+
98
+ #
99
+ # Enqueue worker and delay processing.
100
+ #
101
+ # @param [Time, Integer] time_at The time at which the job should run.
102
+ # @param [Array<any>] *args List of worker arguments
103
+ #
104
+ # @return [Google::Cloud::Tasks::V2beta3::Task] The Google Task response
105
+ #
106
+ def perform_at(time_at, *args)
107
+ new(job_args: args).schedule(time_at: time_at)
108
+ end
109
+ end
110
+
111
+ #
112
+ # Build a new worker instance.
113
+ #
114
+ # @param [Array<any>] job_args The list of perform args.
115
+ # @param [String] job_id A unique ID identifying this job.
116
+ #
117
+ def initialize(job_args: [], job_id: nil, job_meta: {})
118
+ @job_args = job_args
119
+ @job_id = job_id || SecureRandom.uuid
120
+ @job_meta = MetaStore.new(job_meta)
121
+ end
122
+
123
+ #
124
+ # Execute the worker by calling the `perform` with the args.
125
+ #
126
+ # @return [Any] The result of the perform.
127
+ #
128
+ def execute
129
+ Cloudtasker.config.server_middleware.invoke(self) do
130
+ perform(*job_args)
131
+ end
132
+ end
133
+
134
+ #
135
+ # Enqueue a worker, with or without delay.
136
+ #
137
+ # @param [Integer] interval The delay in seconds.
138
+ #
139
+ # @param [Time, Integer] interval The time at which the job should run
140
+ #
141
+ # @return [Google::Cloud::Tasks::V2beta3::Task] The Google Task response
142
+ #
143
+ def schedule(interval: nil, time_at: nil)
144
+ Cloudtasker.config.client_middleware.invoke(self) do
145
+ Task.new(self).schedule(interval: interval, time_at: time_at)
146
+ end
147
+ end
148
+
149
+ #
150
+ # Helper method used to re-enqueue the job. Re-enqueued
151
+ # jobs keep the same job_id.
152
+ #
153
+ # This helper may be useful when jobs must pause activity due to external
154
+ # factors such as when a third-party API is throttling the rate of API calls.
155
+ #
156
+ # @param [Integer] interval Delay to wait before processing the job again (in seconds).
157
+ #
158
+ # @return [Google::Cloud::Tasks::V2beta3::Task] The Google Task response
159
+ #
160
+ def reenqueue(interval)
161
+ @job_reenqueued = true
162
+ schedule(interval: interval)
163
+ end
164
+
165
+ #
166
+ # Return a new instance of the worker with the same args and metadata
167
+ # but with a different id.
168
+ #
169
+ # @return [<Type>] <description>
170
+ #
171
+ def new_instance
172
+ self.class.new(job_args: job_args, job_meta: job_meta)
173
+ end
174
+
175
+ #
176
+ # Return a hash description of the worker.
177
+ #
178
+ # @return [Hash] The worker hash description.
179
+ #
180
+ def to_h
181
+ {
182
+ worker: self.class.to_s,
183
+ job_id: job_id,
184
+ job_args: job_args,
185
+ job_meta: job_meta.to_h
186
+ }
187
+ end
188
+
189
+ #
190
+ # Return a json representation of the worker.
191
+ #
192
+ # @param [Array<any>] *args Arguments passed to to_json.
193
+ #
194
+ # @return [String] The worker json representation.
195
+ #
196
+ def to_json(*args)
197
+ to_h.to_json(*args)
198
+ end
199
+
200
+ #
201
+ # Equality operator.
202
+ #
203
+ # @param [Any] other The object to compare.
204
+ #
205
+ # @return [Boolean] True if the object is equal.
206
+ #
207
+ def ==(other)
208
+ other.is_a?(self.class) && other.job_id == job_id
209
+ end
210
+ end
211
+ end
metadata ADDED
@@ -0,0 +1,286 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudtasker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Arnaud Lachaume
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fugit
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: google-cloud-tasks
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
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: jwt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: redis
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '='
116
+ - !ruby/object:Gem::Version
117
+ version: 0.76.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: 0.76.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: timecop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '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'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rails
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: rspec-rails
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
+ - !ruby/object:Gem::Dependency
182
+ name: sqlite3
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ description: Manage GCP Cloud Tasks in your app.
196
+ email:
197
+ - arnaud.lachaume@keypup.io
198
+ executables: []
199
+ extensions: []
200
+ extra_rdoc_files: []
201
+ files:
202
+ - ".gitignore"
203
+ - ".rspec"
204
+ - ".rubocop.yml"
205
+ - ".travis.yml"
206
+ - CODE_OF_CONDUCT.md
207
+ - Gemfile
208
+ - Gemfile.lock
209
+ - LICENSE.txt
210
+ - README.md
211
+ - Rakefile
212
+ - app/controllers/cloudtasker/application_controller.rb
213
+ - app/controllers/cloudtasker/worker_controller.rb
214
+ - bin/console
215
+ - bin/setup
216
+ - cloudtasker.gemspec
217
+ - config/routes.rb
218
+ - lib/cloudtasker.rb
219
+ - lib/cloudtasker/authentication_error.rb
220
+ - lib/cloudtasker/authenticator.rb
221
+ - lib/cloudtasker/batch.rb
222
+ - lib/cloudtasker/batch/batch_progress.rb
223
+ - lib/cloudtasker/batch/config.rb
224
+ - lib/cloudtasker/batch/extension/worker.rb
225
+ - lib/cloudtasker/batch/job.rb
226
+ - lib/cloudtasker/batch/middleware.rb
227
+ - lib/cloudtasker/batch/middleware/server.rb
228
+ - lib/cloudtasker/config.rb
229
+ - lib/cloudtasker/cron.rb
230
+ - lib/cloudtasker/cron/config.rb
231
+ - lib/cloudtasker/cron/job.rb
232
+ - lib/cloudtasker/cron/middleware.rb
233
+ - lib/cloudtasker/cron/middleware/server.rb
234
+ - lib/cloudtasker/cron/schedule.rb
235
+ - lib/cloudtasker/engine.rb
236
+ - lib/cloudtasker/invalid_worker_error.rb
237
+ - lib/cloudtasker/meta_store.rb
238
+ - lib/cloudtasker/middleware/chain.rb
239
+ - lib/cloudtasker/redis_client.rb
240
+ - lib/cloudtasker/task.rb
241
+ - lib/cloudtasker/unique_job.rb
242
+ - lib/cloudtasker/unique_job/config.rb
243
+ - lib/cloudtasker/unique_job/conflict_strategy/base_strategy.rb
244
+ - lib/cloudtasker/unique_job/conflict_strategy/raise.rb
245
+ - lib/cloudtasker/unique_job/conflict_strategy/reject.rb
246
+ - lib/cloudtasker/unique_job/conflict_strategy/reschedule.rb
247
+ - lib/cloudtasker/unique_job/job.rb
248
+ - lib/cloudtasker/unique_job/lock/base_lock.rb
249
+ - lib/cloudtasker/unique_job/lock/no_op.rb
250
+ - lib/cloudtasker/unique_job/lock/until_executed.rb
251
+ - lib/cloudtasker/unique_job/lock/until_executing.rb
252
+ - lib/cloudtasker/unique_job/lock/while_executing.rb
253
+ - lib/cloudtasker/unique_job/lock_error.rb
254
+ - lib/cloudtasker/unique_job/middleware.rb
255
+ - lib/cloudtasker/unique_job/middleware/client.rb
256
+ - lib/cloudtasker/unique_job/middleware/server.rb
257
+ - lib/cloudtasker/version.rb
258
+ - lib/cloudtasker/worker.rb
259
+ homepage: https://github.com/keypup-io/cloudtasker
260
+ licenses:
261
+ - MIT
262
+ metadata:
263
+ homepage_uri: https://github.com/keypup-io/cloudtasker
264
+ source_code_uri: https://github.com/keypup-io/cloudtasker
265
+ changelog_uri: https://github.com/keypup-io/cloudtasker/master/tree/CHANGELOG.md
266
+ post_install_message:
267
+ rdoc_options: []
268
+ require_paths:
269
+ - lib
270
+ required_ruby_version: !ruby/object:Gem::Requirement
271
+ requirements:
272
+ - - ">="
273
+ - !ruby/object:Gem::Version
274
+ version: '0'
275
+ required_rubygems_version: !ruby/object:Gem::Requirement
276
+ requirements:
277
+ - - ">="
278
+ - !ruby/object:Gem::Version
279
+ version: '0'
280
+ requirements: []
281
+ rubyforge_project:
282
+ rubygems_version: 2.7.9
283
+ signing_key:
284
+ specification_version: 4
285
+ summary: Manage GCP Cloud Tasks in your app.
286
+ test_files: []