cloudtasker 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.rubocop.yml +5 -0
  4. data/.travis.yml +10 -1
  5. data/Appraisals +25 -0
  6. data/Gemfile.lock +10 -4
  7. data/README.md +550 -4
  8. data/app/controllers/cloudtasker/application_controller.rb +2 -0
  9. data/app/controllers/cloudtasker/worker_controller.rb +22 -2
  10. data/cloudtasker.gemspec +4 -3
  11. data/docs/BATCH_JOBS.md +66 -0
  12. data/docs/CRON_JOBS.md +63 -0
  13. data/docs/UNIQUE_JOBS.md +127 -0
  14. data/exe/cloudtasker +15 -0
  15. data/gemfiles/.bundle/config +2 -0
  16. data/gemfiles/google_cloud_tasks_1.0.gemfile +9 -0
  17. data/gemfiles/google_cloud_tasks_1.0.gemfile.lock +263 -0
  18. data/gemfiles/google_cloud_tasks_1.1.gemfile +9 -0
  19. data/gemfiles/google_cloud_tasks_1.1.gemfile.lock +263 -0
  20. data/gemfiles/google_cloud_tasks_1.2.gemfile +9 -0
  21. data/gemfiles/google_cloud_tasks_1.2.gemfile.lock +263 -0
  22. data/gemfiles/google_cloud_tasks_1.3.gemfile +9 -0
  23. data/gemfiles/google_cloud_tasks_1.3.gemfile.lock +264 -0
  24. data/gemfiles/rails_4.0.gemfile +10 -0
  25. data/gemfiles/rails_4.1.gemfile +9 -0
  26. data/gemfiles/rails_4.2.gemfile +9 -0
  27. data/gemfiles/rails_5.0.gemfile +9 -0
  28. data/gemfiles/rails_5.1.gemfile +9 -0
  29. data/gemfiles/rails_5.2.gemfile +9 -0
  30. data/gemfiles/rails_5.2.gemfile.lock +247 -0
  31. data/gemfiles/rails_6.0.gemfile +9 -0
  32. data/gemfiles/rails_6.0.gemfile.lock +263 -0
  33. data/lib/cloudtasker.rb +19 -1
  34. data/lib/cloudtasker/backend/google_cloud_task.rb +139 -0
  35. data/lib/cloudtasker/backend/memory_task.rb +190 -0
  36. data/lib/cloudtasker/backend/redis_task.rb +248 -0
  37. data/lib/cloudtasker/batch/batch_progress.rb +19 -1
  38. data/lib/cloudtasker/batch/job.rb +81 -20
  39. data/lib/cloudtasker/cli.rb +194 -0
  40. data/lib/cloudtasker/cloud_task.rb +91 -0
  41. data/lib/cloudtasker/config.rb +64 -2
  42. data/lib/cloudtasker/cron/job.rb +2 -2
  43. data/lib/cloudtasker/cron/schedule.rb +15 -5
  44. data/lib/cloudtasker/dead_worker_error.rb +6 -0
  45. data/lib/cloudtasker/local_server.rb +74 -0
  46. data/lib/cloudtasker/railtie.rb +10 -0
  47. data/lib/cloudtasker/testing.rb +133 -0
  48. data/lib/cloudtasker/unique_job/job.rb +1 -1
  49. data/lib/cloudtasker/unique_job/lock/base_lock.rb +1 -1
  50. data/lib/cloudtasker/unique_job/lock/until_executed.rb +3 -1
  51. data/lib/cloudtasker/unique_job/lock/while_executing.rb +3 -1
  52. data/lib/cloudtasker/version.rb +1 -1
  53. data/lib/cloudtasker/worker.rb +59 -16
  54. data/lib/cloudtasker/{task.rb → worker_handler.rb} +10 -77
  55. data/lib/cloudtasker/worker_logger.rb +155 -0
  56. data/lib/tasks/setup_queue.rake +10 -0
  57. metadata +55 -6
@@ -3,39 +3,13 @@
3
3
  require 'google/cloud/tasks'
4
4
 
5
5
  module Cloudtasker
6
- # Build, serialize and schedule tasks on GCP Cloud Task
7
- class Task
6
+ # Build, serialize and schedule tasks on the processing backend.
7
+ class WorkerHandler
8
8
  attr_reader :worker, :job_args
9
9
 
10
10
  # Alrogith used to sign the verification token
11
11
  JWT_ALG = 'HS256'
12
12
 
13
- # TODO: Move to a dedicated CloudTask class
14
- #
15
- # Find a Cloud task
16
- #
17
- # @param [String] id The ID of the task.
18
- #
19
- # @return [Google::Cloud::Tasks::V2beta3::Task] The cloud task.
20
- #
21
- def self.find(id)
22
- client.get_task(id)
23
- rescue Google::Gax::RetryError
24
- nil
25
- end
26
-
27
- # TODO: Move to a dedicated CloudTask class
28
- #
29
- # Delete a Cloud task
30
- #
31
- # @param [String] id The ID of the task.
32
- #
33
- def self.delete(id)
34
- client.delete_task(id)
35
- rescue Google::Gax::RetryError
36
- nil
37
- end
38
-
39
13
  #
40
14
  # Execute a task worker from a task payload
41
15
  #
@@ -48,15 +22,6 @@ module Cloudtasker
48
22
  worker.execute
49
23
  end
50
24
 
51
- #
52
- # Return the Google Cloud Task client.
53
- #
54
- # @return [Google::Cloud::Tasks] The Google Cloud Task client.
55
- #
56
- def self.client
57
- @client ||= ::Google::Cloud::Tasks.new(version: :v2beta3)
58
- end
59
-
60
25
  #
61
26
  # Prepare a new cloud task.
62
27
  #
@@ -66,37 +31,6 @@ module Cloudtasker
66
31
  @worker = worker
67
32
  end
68
33
 
69
- #
70
- # Return the Google Cloud Task client.
71
- #
72
- # @return [Google::Cloud::Tasks] The Google Cloud Task client.
73
- #
74
- def client
75
- self.class.client
76
- end
77
-
78
- #
79
- # Return the cloudtasker configuration. See Cloudtasker#configure.
80
- #
81
- # @return [Cloudtasker::Config] The library configuration.
82
- #
83
- def config
84
- Cloudtasker.config
85
- end
86
-
87
- #
88
- # Return the fully qualified path for the Cloud Task queue.
89
- #
90
- # @return [String] The queue path.
91
- #
92
- def queue_path
93
- client.queue_path(
94
- config.gcp_project_id,
95
- config.gcp_location_id,
96
- config.gcp_queue_id
97
- )
98
- end
99
-
100
34
  #
101
35
  # Return the full task configuration sent to Cloud Task
102
36
  #
@@ -106,7 +40,7 @@ module Cloudtasker
106
40
  {
107
41
  http_request: {
108
42
  http_method: 'POST',
109
- url: config.processor_url,
43
+ url: Cloudtasker.config.processor_url,
110
44
  headers: {
111
45
  'Content-Type' => 'application/json',
112
46
  'Authorization' => "Bearer #{Authenticator.verification_token}"
@@ -133,7 +67,7 @@ module Cloudtasker
133
67
  worker: worker.class.to_s,
134
68
  job_id: worker.job_id,
135
69
  job_args: worker.job_args,
136
- job_meta: worker.job_meta
70
+ job_meta: worker.job_meta.to_h
137
71
  }
138
72
  end
139
73
 
@@ -142,16 +76,15 @@ module Cloudtasker
142
76
  # before running a task.
143
77
  #
144
78
  # @param [Integer, nil] interval The time to wait.
79
+ # @param [Integer, nil] time_at The time at which the job should run.
145
80
  #
146
- # @return [Google::Protobuf::Timestamp, nil] The protobuff timestamp
81
+ # @return [Integer, nil] The Unix timestamp.
147
82
  #
148
83
  def schedule_time(interval: nil, time_at: nil)
149
84
  return nil unless interval || time_at
150
85
 
151
- # Generate protobuf timestamp
152
- timestamp = Google::Protobuf::Timestamp.new
153
- timestamp.seconds = (time_at || Time.now).to_i + interval.to_i
154
- timestamp
86
+ # Generate the complete Unix timestamp
87
+ (time_at || Time.now).to_i + interval.to_i
155
88
  end
156
89
 
157
90
  #
@@ -160,7 +93,7 @@ module Cloudtasker
160
93
  # @param [Integer, nil] interval How to wait before running the task.
161
94
  # Leave to `nil` to run now.
162
95
  #
163
- # @return [Google::Cloud::Tasks::V2beta3::Task] The Google Task response
96
+ # @return [Cloudtasker::CloudTask] The Google Task response
164
97
  #
165
98
  def schedule(interval: nil, time_at: nil)
166
99
  # Generate task payload
@@ -169,7 +102,7 @@ module Cloudtasker
169
102
  ).compact
170
103
 
171
104
  # Create and return remote task
172
- client.create_task(queue_path, task)
105
+ CloudTask.create(task)
173
106
  end
174
107
  end
175
108
  end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudtasker
4
+ # Add contextual information to logs generated
5
+ # by workers
6
+ class WorkerLogger
7
+ attr_accessor :worker
8
+
9
+ class << self
10
+ attr_accessor :log_context_processor
11
+ end
12
+
13
+ # Only log the job meta information by default (exclude arguments)
14
+ DEFAULT_CONTEXT_PROCESSOR = ->(worker) { worker.to_h.slice(:worker, :job_id, :job_meta) }
15
+
16
+ #
17
+ # Build a new instance of the class.
18
+ #
19
+ # @param [Cloudtasker::Worker] worker The worker.
20
+ #
21
+ def initialize(worker)
22
+ @worker = worker
23
+ end
24
+
25
+ #
26
+ # Return the Proc responsible for formatting the log payload.
27
+ #
28
+ # @return [Proc] The context processor.
29
+ #
30
+ def context_processor
31
+ @context_processor ||= worker.class.cloudtasker_options_hash[:log_context_processor] ||
32
+ self.class.log_context_processor ||
33
+ DEFAULT_CONTEXT_PROCESSOR
34
+ end
35
+
36
+ #
37
+ # The block to pass to log messages.
38
+ #
39
+ # @return [Proc] The log block.
40
+ #
41
+ def log_block
42
+ @log_block ||= proc { context_processor.call(worker) }
43
+ end
44
+
45
+ #
46
+ # Return the Cloudtasker logger.
47
+ #
48
+ # @return [Logger, any] The cloudtasker logger.
49
+ #
50
+ def logger
51
+ Cloudtasker.logger
52
+ end
53
+
54
+ #
55
+ # Format main log message.
56
+ #
57
+ # @param [String] msg The message to log.
58
+ #
59
+ # @return [String] The formatted log message
60
+ #
61
+ def formatted_message(msg)
62
+ "[Cloudtasker][#{worker.job_id}] #{msg}"
63
+ end
64
+
65
+ #
66
+ # Log an info message.
67
+ #
68
+ # @param [String] msg The message to log.
69
+ # @param [Proc] &block Optional context block.
70
+ #
71
+ def info(msg, &block)
72
+ log_message(:info, msg, &block)
73
+ end
74
+
75
+ #
76
+ # Log an error message.
77
+ #
78
+ # @param [String] msg The message to log.
79
+ # @param [Proc] &block Optional context block.
80
+ #
81
+ def error(msg, &block)
82
+ log_message(:error, msg, &block)
83
+ end
84
+
85
+ #
86
+ # Log an fatal message.
87
+ #
88
+ # @param [String] msg The message to log.
89
+ # @param [Proc] &block Optional context block.
90
+ #
91
+ def fatal(msg, &block)
92
+ log_message(:fatal, msg, &block)
93
+ end
94
+
95
+ #
96
+ # Log an debut message.
97
+ #
98
+ # @param [String] msg The message to log.
99
+ # @param [Proc] &block Optional context block.
100
+ #
101
+ def debug(msg, &block)
102
+ log_message(:debug, msg, &block)
103
+ end
104
+
105
+ #
106
+ # Delegate all methods to the underlying logger.
107
+ #
108
+ # @param [String, Symbol] name The method to delegate.
109
+ # @param [Array<any>] *args The list of method arguments.
110
+ # @param [Proc] &block Block passed to the method.
111
+ #
112
+ # @return [Any] The method return value
113
+ #
114
+ def method_missing(name, *args, &block)
115
+ if logger.respond_to?(name)
116
+ logger.send(name, *args, &block)
117
+ else
118
+ super
119
+ end
120
+ end
121
+
122
+ #
123
+ # Check if the class respond to a certain method.
124
+ #
125
+ # @param [String, Symbol] name The name of the method.
126
+ # @param [Boolean] include_private Whether to check private methods or not. Default to false.
127
+ #
128
+ # @return [Boolean] Return true if the class respond to this method.
129
+ #
130
+ def respond_to_missing?(name, include_private = false)
131
+ logger.respond_to?(name) || super
132
+ end
133
+
134
+ private
135
+
136
+ #
137
+ # Log a message for the provided log level.
138
+ #
139
+ # @param [String, Symbol] level The log level
140
+ # @param [String] msg The message to log.
141
+ # @param [Proc] &block Optional context block.
142
+ #
143
+ def log_message(level, msg, &block)
144
+ payload_block = block || log_block
145
+
146
+ # ActiveSupport::Logger does not support passing a payload through a block on top
147
+ # of a message.
148
+ if defined?(ActiveSupport::Logger) && logger.is_a?(ActiveSupport::Logger)
149
+ logger.send(level) { "#{formatted_message(msg)} -- #{payload_block.call}" }
150
+ else
151
+ logger.send(level, formatted_message(msg), &payload_block)
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cloudtasker/backend/google_cloud_task'
4
+
5
+ namespace :cloudtasker do
6
+ desc 'Setup the Cloud Task queue'
7
+ task setup_queue: :environment do
8
+ Cloudtasker::Backend::GoogleCloudTask.setup_queue
9
+ end
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudtasker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arnaud Lachaume
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-18 00:00:00.000000000 Z
11
+ date: 2019-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: appraisal
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'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: bundler
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -220,10 +234,11 @@ dependencies:
220
234
  - - ">="
221
235
  - !ruby/object:Gem::Version
222
236
  version: '0'
223
- description: Manage GCP Cloud Tasks in your app. (under development)
237
+ description: Manage GCP Cloud Tasks in your app. (alpha)
224
238
  email:
225
239
  - arnaud.lachaume@keypup.io
226
- executables: []
240
+ executables:
241
+ - cloudtasker
227
242
  extensions: []
228
243
  extra_rdoc_files: []
229
244
  files:
@@ -231,6 +246,7 @@ files:
231
246
  - ".rspec"
232
247
  - ".rubocop.yml"
233
248
  - ".travis.yml"
249
+ - Appraisals
234
250
  - CODE_OF_CONDUCT.md
235
251
  - Gemfile
236
252
  - Gemfile.lock
@@ -243,27 +259,57 @@ files:
243
259
  - bin/setup
244
260
  - cloudtasker.gemspec
245
261
  - config/routes.rb
262
+ - docs/BATCH_JOBS.md
263
+ - docs/CRON_JOBS.md
264
+ - docs/UNIQUE_JOBS.md
265
+ - exe/cloudtasker
266
+ - gemfiles/.bundle/config
267
+ - gemfiles/google_cloud_tasks_1.0.gemfile
268
+ - gemfiles/google_cloud_tasks_1.0.gemfile.lock
269
+ - gemfiles/google_cloud_tasks_1.1.gemfile
270
+ - gemfiles/google_cloud_tasks_1.1.gemfile.lock
271
+ - gemfiles/google_cloud_tasks_1.2.gemfile
272
+ - gemfiles/google_cloud_tasks_1.2.gemfile.lock
273
+ - gemfiles/google_cloud_tasks_1.3.gemfile
274
+ - gemfiles/google_cloud_tasks_1.3.gemfile.lock
275
+ - gemfiles/rails_4.0.gemfile
276
+ - gemfiles/rails_4.1.gemfile
277
+ - gemfiles/rails_4.2.gemfile
278
+ - gemfiles/rails_5.0.gemfile
279
+ - gemfiles/rails_5.1.gemfile
280
+ - gemfiles/rails_5.2.gemfile
281
+ - gemfiles/rails_5.2.gemfile.lock
282
+ - gemfiles/rails_6.0.gemfile
283
+ - gemfiles/rails_6.0.gemfile.lock
246
284
  - lib/cloudtasker.rb
247
285
  - lib/cloudtasker/authentication_error.rb
248
286
  - lib/cloudtasker/authenticator.rb
287
+ - lib/cloudtasker/backend/google_cloud_task.rb
288
+ - lib/cloudtasker/backend/memory_task.rb
289
+ - lib/cloudtasker/backend/redis_task.rb
249
290
  - lib/cloudtasker/batch.rb
250
291
  - lib/cloudtasker/batch/batch_progress.rb
251
292
  - lib/cloudtasker/batch/extension/worker.rb
252
293
  - lib/cloudtasker/batch/job.rb
253
294
  - lib/cloudtasker/batch/middleware.rb
254
295
  - lib/cloudtasker/batch/middleware/server.rb
296
+ - lib/cloudtasker/cli.rb
297
+ - lib/cloudtasker/cloud_task.rb
255
298
  - lib/cloudtasker/config.rb
256
299
  - lib/cloudtasker/cron.rb
257
300
  - lib/cloudtasker/cron/job.rb
258
301
  - lib/cloudtasker/cron/middleware.rb
259
302
  - lib/cloudtasker/cron/middleware/server.rb
260
303
  - lib/cloudtasker/cron/schedule.rb
304
+ - lib/cloudtasker/dead_worker_error.rb
261
305
  - lib/cloudtasker/engine.rb
262
306
  - lib/cloudtasker/invalid_worker_error.rb
307
+ - lib/cloudtasker/local_server.rb
263
308
  - lib/cloudtasker/meta_store.rb
264
309
  - lib/cloudtasker/middleware/chain.rb
310
+ - lib/cloudtasker/railtie.rb
265
311
  - lib/cloudtasker/redis_client.rb
266
- - lib/cloudtasker/task.rb
312
+ - lib/cloudtasker/testing.rb
267
313
  - lib/cloudtasker/unique_job.rb
268
314
  - lib/cloudtasker/unique_job/conflict_strategy/base_strategy.rb
269
315
  - lib/cloudtasker/unique_job/conflict_strategy/raise.rb
@@ -281,6 +327,9 @@ files:
281
327
  - lib/cloudtasker/unique_job/middleware/server.rb
282
328
  - lib/cloudtasker/version.rb
283
329
  - lib/cloudtasker/worker.rb
330
+ - lib/cloudtasker/worker_handler.rb
331
+ - lib/cloudtasker/worker_logger.rb
332
+ - lib/tasks/setup_queue.rake
284
333
  homepage: https://github.com/keypup-io/cloudtasker
285
334
  licenses:
286
335
  - MIT
@@ -307,5 +356,5 @@ rubyforge_project:
307
356
  rubygems_version: 2.7.9
308
357
  signing_key:
309
358
  specification_version: 4
310
- summary: Manage GCP Cloud Tasks in your app. (under development)
359
+ summary: Manage GCP Cloud Tasks in your app. (alpha)
311
360
  test_files: []