cloudtasker 0.9.5 → 0.10.rc1

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +16 -0
  4. data/Appraisals +0 -16
  5. data/CHANGELOG.md +0 -22
  6. data/README.md +40 -1
  7. data/app/controllers/cloudtasker/application_controller.rb +8 -0
  8. data/app/controllers/cloudtasker/worker_controller.rb +1 -4
  9. data/cloudtasker.gemspec +1 -2
  10. data/gemfiles/google_cloud_tasks_1.0.gemfile +5 -3
  11. data/gemfiles/google_cloud_tasks_1.0.gemfile.lock +154 -208
  12. data/gemfiles/google_cloud_tasks_1.1.gemfile +5 -3
  13. data/gemfiles/google_cloud_tasks_1.1.gemfile.lock +154 -208
  14. data/gemfiles/google_cloud_tasks_1.2.gemfile +5 -3
  15. data/gemfiles/google_cloud_tasks_1.2.gemfile.lock +154 -208
  16. data/gemfiles/google_cloud_tasks_1.3.gemfile +5 -3
  17. data/gemfiles/google_cloud_tasks_1.3.gemfile.lock +154 -208
  18. data/gemfiles/rails_5.2.gemfile +5 -3
  19. data/gemfiles/rails_5.2.gemfile.lock +91 -146
  20. data/gemfiles/rails_6.0.gemfile +5 -3
  21. data/gemfiles/rails_6.0.gemfile.lock +92 -147
  22. data/lib/cloudtasker/backend/google_cloud_task.rb +1 -1
  23. data/lib/cloudtasker/backend/memory_task.rb +8 -23
  24. data/lib/cloudtasker/config.rb +16 -1
  25. data/lib/cloudtasker/testing.rb +2 -2
  26. data/lib/cloudtasker/version.rb +1 -1
  27. data/lib/cloudtasker/worker_handler.rb +142 -5
  28. data/lib/cloudtasker/worker_logger.rb +1 -2
  29. data/lib/cloudtasker.rb +0 -1
  30. metadata +15 -32
  31. data/.github/workflows/test.yml +0 -45
  32. data/gemfiles/semantic_logger_3.4.gemfile +0 -7
  33. data/gemfiles/semantic_logger_4.6.gemfile +0 -7
  34. data/gemfiles/semantic_logger_4.7.0.gemfile +0 -7
  35. data/gemfiles/semantic_logger_4.7.2.gemfile +0 -7
  36. data/gemfiles/semantic_logger_4.7.gemfile +0 -9
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- cloudtasker (0.9.4)
4
+ cloudtasker (0.10.rc1)
5
5
  activesupport
6
6
  fugit
7
- google-cloud-tasks (~> 1.0)
7
+ google-cloud-tasks
8
8
  jwt
9
9
  redis
10
10
 
@@ -66,79 +66,40 @@ GEM
66
66
  minitest (~> 5.1)
67
67
  tzinfo (~> 1.1)
68
68
  zeitwerk (~> 2.1, >= 2.1.8)
69
- addressable (2.8.0)
69
+ addressable (2.7.0)
70
70
  public_suffix (>= 2.0.2, < 5.0)
71
- appraisal (2.4.1)
71
+ appraisal (2.2.0)
72
72
  bundler
73
73
  rake
74
74
  thor (>= 0.14.0)
75
- ast (2.4.2)
76
- async (1.30.1)
77
- console (~> 1.10)
78
- nio4r (~> 2.3)
79
- timers (~> 4.1)
80
- async-http (0.56.5)
81
- async (>= 1.25)
82
- async-io (>= 1.28)
83
- async-pool (>= 0.2)
84
- protocol-http (~> 0.22.0)
85
- protocol-http1 (~> 0.14.0)
86
- protocol-http2 (~> 0.14.0)
87
- async-http-faraday (0.11.0)
88
- async-http (~> 0.42)
89
- faraday
90
- async-io (1.32.2)
91
- async
92
- async-pool (0.3.8)
93
- async (>= 1.25)
75
+ ast (2.4.0)
94
76
  builder (3.2.4)
95
- concurrent-ruby (1.1.9)
96
- console (1.13.1)
97
- fiber-local
98
- crack (0.4.5)
99
- rexml
77
+ concurrent-ruby (1.1.6)
78
+ crack (0.4.3)
79
+ safe_yaml (~> 1.0.0)
100
80
  crass (1.0.6)
101
- diff-lcs (1.4.4)
102
- erubi (1.10.0)
103
- et-orbi (1.2.4)
81
+ diff-lcs (1.3)
82
+ erubi (1.9.0)
83
+ et-orbi (1.2.3)
104
84
  tzinfo
105
- faraday (1.7.0)
106
- faraday-em_http (~> 1.0)
107
- faraday-em_synchrony (~> 1.0)
108
- faraday-excon (~> 1.1)
109
- faraday-httpclient (~> 1.0.1)
110
- faraday-net_http (~> 1.0)
111
- faraday-net_http_persistent (~> 1.1)
112
- faraday-patron (~> 1.0)
113
- faraday-rack (~> 1.0)
85
+ faraday (0.17.3)
114
86
  multipart-post (>= 1.2, < 3)
115
- ruby2_keywords (>= 0.0.4)
116
- faraday-em_http (1.0.0)
117
- faraday-em_synchrony (1.0.0)
118
- faraday-excon (1.1.0)
119
- faraday-http-cache (2.2.0)
120
- faraday (>= 0.8)
121
- faraday-httpclient (1.0.1)
122
- faraday-net_http (1.0.1)
123
- faraday-net_http_persistent (1.2.0)
124
- faraday-patron (1.0.0)
125
- faraday-rack (1.0.0)
126
- fiber-local (1.0.0)
127
- fugit (1.5.1)
87
+ faraday-http-cache (2.0.0)
88
+ faraday (~> 0.8)
89
+ fugit (1.3.3)
128
90
  et-orbi (~> 1.1, >= 1.1.8)
129
- raabro (~> 1.4)
130
- github_changelog_generator (1.16.4)
91
+ raabro (~> 1.1)
92
+ github_changelog_generator (1.15.0)
131
93
  activesupport
132
- async (>= 1.25.0)
133
- async-http-faraday
134
94
  faraday-http-cache
135
95
  multi_json
136
96
  octokit (~> 4.6)
137
97
  rainbow (>= 2.2.1)
138
98
  rake (>= 10.0)
139
- globalid (0.5.2)
140
- activesupport (>= 5.0)
141
- google-cloud-tasks (1.5.1)
99
+ retriable (~> 3.0)
100
+ globalid (0.4.2)
101
+ activesupport (>= 4.2.0)
102
+ google-cloud-tasks (1.4.0)
142
103
  google-gax (~> 1.8)
143
104
  googleapis-common-protos (>= 1.3.9, < 2.0)
144
105
  googleapis-common-protos-types (>= 1.0.4, < 2.0)
@@ -149,33 +110,32 @@ GEM
149
110
  googleauth (~> 0.9)
150
111
  grpc (~> 1.24)
151
112
  rly (~> 0.2.3)
152
- google-protobuf (3.17.3)
153
- googleapis-common-protos (1.3.11)
154
- google-protobuf (~> 3.14)
155
- googleapis-common-protos-types (>= 1.0.6, < 2.0)
156
- grpc (~> 1.27)
157
- googleapis-common-protos-types (1.1.0)
158
- google-protobuf (~> 3.14)
159
- googleauth (0.17.0)
113
+ google-protobuf (3.11.4)
114
+ googleapis-common-protos (1.3.9)
115
+ google-protobuf (~> 3.0)
116
+ googleapis-common-protos-types (~> 1.0)
117
+ grpc (~> 1.0)
118
+ googleapis-common-protos-types (1.0.4)
119
+ google-protobuf (~> 3.0)
120
+ googleauth (0.11.0)
160
121
  faraday (>= 0.17.3, < 2.0)
161
122
  jwt (>= 1.4, < 3.0)
162
123
  memoist (~> 0.16)
163
124
  multi_json (~> 1.11)
164
125
  os (>= 0.9, < 2.0)
165
- signet (~> 0.14)
166
- grpc (1.38.0)
167
- google-protobuf (~> 3.15)
126
+ signet (~> 0.12)
127
+ grpc (1.27.0)
128
+ google-protobuf (~> 3.11)
168
129
  googleapis-common-protos-types (~> 1.0)
169
- grpc-google-iam-v1 (0.6.11)
170
- google-protobuf (~> 3.14)
171
- googleapis-common-protos (>= 1.3.11, < 2.0)
172
- grpc (~> 1.27)
130
+ grpc-google-iam-v1 (0.6.9)
131
+ googleapis-common-protos (>= 1.3.1, < 2.0)
132
+ grpc (~> 1.0)
173
133
  hashdiff (1.0.1)
174
- i18n (1.8.10)
134
+ i18n (1.8.2)
175
135
  concurrent-ruby (~> 1.0)
176
136
  jaro_winkler (1.5.4)
177
- jwt (2.2.3)
178
- loofah (2.12.0)
137
+ jwt (2.2.1)
138
+ loofah (2.4.0)
179
139
  crass (~> 1.0.2)
180
140
  nokogiri (>= 1.5.9)
181
141
  mail (2.7.1)
@@ -183,37 +143,26 @@ GEM
183
143
  marcel (0.3.3)
184
144
  mimemagic (~> 0.3.2)
185
145
  memoist (0.16.2)
186
- method_source (1.0.0)
187
- mimemagic (0.3.10)
188
- nokogiri (~> 1)
189
- rake
190
- mini_mime (1.1.0)
191
- mini_portile2 (2.6.1)
192
- minitest (5.14.4)
193
- multi_json (1.15.0)
146
+ method_source (0.9.2)
147
+ mimemagic (0.3.4)
148
+ mini_mime (1.0.2)
149
+ mini_portile2 (2.4.0)
150
+ minitest (5.14.0)
151
+ multi_json (1.14.1)
194
152
  multipart-post (2.1.1)
195
- nio4r (2.5.8)
196
- nokogiri (1.12.3)
197
- mini_portile2 (~> 2.6.1)
198
- racc (~> 1.4)
199
- octokit (4.21.0)
153
+ nio4r (2.5.2)
154
+ nokogiri (1.10.9)
155
+ mini_portile2 (~> 2.4.0)
156
+ octokit (4.16.0)
200
157
  faraday (>= 0.9)
201
158
  sawyer (~> 0.8.0, >= 0.5.3)
202
- os (1.1.1)
203
- parallel (1.20.1)
204
- parser (3.0.2.0)
205
- ast (~> 2.4.1)
206
- protocol-hpack (1.4.2)
207
- protocol-http (0.22.5)
208
- protocol-http1 (0.14.1)
209
- protocol-http (~> 0.22)
210
- protocol-http2 (0.14.2)
211
- protocol-hpack (~> 1.4)
212
- protocol-http (~> 0.18)
213
- public_suffix (4.0.6)
214
- raabro (1.4.0)
215
- racc (1.5.2)
216
- rack (2.2.3)
159
+ os (1.0.1)
160
+ parallel (1.19.1)
161
+ parser (2.7.0.4)
162
+ ast (~> 2.4.0)
163
+ public_suffix (4.0.3)
164
+ raabro (1.1.6)
165
+ rack (2.2.2)
217
166
  rack-test (1.1.0)
218
167
  rack (>= 1.0, < 3)
219
168
  rails (6.0.0)
@@ -234,7 +183,7 @@ GEM
234
183
  rails-dom-testing (2.0.3)
235
184
  activesupport (>= 4.2.0)
236
185
  nokogiri (>= 1.6)
237
- rails-html-sanitizer (1.4.1)
186
+ rails-html-sanitizer (1.3.0)
238
187
  loofah (~> 2.3)
239
188
  railties (6.0.0)
240
189
  actionpack (= 6.0.0)
@@ -243,31 +192,31 @@ GEM
243
192
  rake (>= 0.8.7)
244
193
  thor (>= 0.20.3, < 2.0)
245
194
  rainbow (3.0.0)
246
- rake (13.0.6)
247
- redis (4.4.0)
248
- rexml (3.2.5)
195
+ rake (13.0.1)
196
+ redis (4.1.3)
197
+ retriable (3.1.2)
249
198
  rly (0.2.3)
250
- rspec (3.10.0)
251
- rspec-core (~> 3.10.0)
252
- rspec-expectations (~> 3.10.0)
253
- rspec-mocks (~> 3.10.0)
254
- rspec-core (3.10.1)
255
- rspec-support (~> 3.10.0)
256
- rspec-expectations (3.10.1)
199
+ rspec (3.9.0)
200
+ rspec-core (~> 3.9.0)
201
+ rspec-expectations (~> 3.9.0)
202
+ rspec-mocks (~> 3.9.0)
203
+ rspec-core (3.9.1)
204
+ rspec-support (~> 3.9.1)
205
+ rspec-expectations (3.9.0)
257
206
  diff-lcs (>= 1.2.0, < 2.0)
258
- rspec-support (~> 3.10.0)
259
- rspec-mocks (3.10.2)
207
+ rspec-support (~> 3.9.0)
208
+ rspec-mocks (3.9.1)
260
209
  diff-lcs (>= 1.2.0, < 2.0)
261
- rspec-support (~> 3.10.0)
262
- rspec-rails (5.0.2)
263
- actionpack (>= 5.2)
264
- activesupport (>= 5.2)
265
- railties (>= 5.2)
266
- rspec-core (~> 3.10)
267
- rspec-expectations (~> 3.10)
268
- rspec-mocks (~> 3.10)
269
- rspec-support (~> 3.10)
270
- rspec-support (3.10.2)
210
+ rspec-support (~> 3.9.0)
211
+ rspec-rails (3.9.0)
212
+ actionpack (>= 3.0)
213
+ activesupport (>= 3.0)
214
+ railties (>= 3.0)
215
+ rspec-core (~> 3.9.0)
216
+ rspec-expectations (~> 3.9.0)
217
+ rspec-mocks (~> 3.9.0)
218
+ rspec-support (~> 3.9.0)
219
+ rspec-support (3.9.2)
271
220
  rubocop (0.76.0)
272
221
  jaro_winkler (~> 1.5.1)
273
222
  parallel (~> 1.10)
@@ -277,41 +226,38 @@ GEM
277
226
  unicode-display_width (>= 1.4.0, < 1.7)
278
227
  rubocop-rspec (1.37.0)
279
228
  rubocop (>= 0.68.1)
280
- ruby-progressbar (1.11.0)
281
- ruby2_keywords (0.0.5)
229
+ ruby-progressbar (1.10.1)
230
+ safe_yaml (1.0.5)
282
231
  sawyer (0.8.2)
283
232
  addressable (>= 2.3.5)
284
233
  faraday (> 0.8, < 2.0)
285
- semantic_logger (4.8.2)
286
- concurrent-ruby (~> 1.0)
287
- signet (0.15.0)
234
+ signet (0.13.0)
288
235
  addressable (~> 2.3)
289
236
  faraday (>= 0.17.3, < 2.0)
290
237
  jwt (>= 1.5, < 3.0)
291
238
  multi_json (~> 1.10)
292
- sprockets (4.0.2)
239
+ sprockets (4.0.0)
293
240
  concurrent-ruby (~> 1.0)
294
241
  rack (> 1, < 3)
295
- sprockets-rails (3.2.2)
242
+ sprockets-rails (3.2.1)
296
243
  actionpack (>= 4.0)
297
244
  activesupport (>= 4.0)
298
245
  sprockets (>= 3.0.0)
299
246
  sqlite3 (1.4.2)
300
- thor (1.1.0)
247
+ thor (1.0.1)
301
248
  thread_safe (0.3.6)
302
- timecop (0.9.4)
303
- timers (4.3.3)
304
- tzinfo (1.2.9)
249
+ timecop (0.9.1)
250
+ tzinfo (1.2.6)
305
251
  thread_safe (~> 0.1)
306
252
  unicode-display_width (1.6.1)
307
- webmock (3.14.0)
308
- addressable (>= 2.8.0)
253
+ webmock (3.8.2)
254
+ addressable (>= 2.3.6)
309
255
  crack (>= 0.3.2)
310
256
  hashdiff (>= 0.4.0, < 2.0.0)
311
- websocket-driver (0.7.5)
257
+ websocket-driver (0.7.1)
312
258
  websocket-extensions (>= 0.1.0)
313
- websocket-extensions (0.1.5)
314
- zeitwerk (2.4.2)
259
+ websocket-extensions (0.1.4)
260
+ zeitwerk (2.3.0)
315
261
 
316
262
  PLATFORMS
317
263
  ruby
@@ -327,10 +273,9 @@ DEPENDENCIES
327
273
  rspec-rails
328
274
  rubocop (= 0.76.0)
329
275
  rubocop-rspec (= 1.37.0)
330
- semantic_logger
331
276
  sqlite3
332
277
  timecop
333
278
  webmock
334
279
 
335
280
  BUNDLED WITH
336
- 2.2.9
281
+ 2.1.4
@@ -146,7 +146,7 @@ module Cloudtasker
146
146
  #
147
147
  def self.delete(id)
148
148
  client.delete_task(id)
149
- rescue Google::Gax::RetryError, GRPC::NotFound
149
+ rescue Google::Gax::RetryError, GRPC::NotFound, Google::Gax::PermissionDeniedError
150
150
  nil
151
151
  end
152
152
 
@@ -7,6 +7,7 @@ module Cloudtasker
7
7
  # Manage local tasks pushed to memory.
8
8
  # Used for testing.
9
9
  class MemoryTask
10
+ attr_accessor :job_retries
10
11
  attr_reader :id, :http_request, :schedule_time, :queue
11
12
 
12
13
  #
@@ -18,17 +19,6 @@ module Cloudtasker
18
19
  @queue ||= []
19
20
  end
20
21
 
21
- #
22
- # Return the workers currently in the queue.
23
- #
24
- # @param [String] worker_class_name Filter jobs on worker class name.
25
- #
26
- # @return [Array<Cloudtasker::Worker] The list of workers
27
- #
28
- def self.jobs(worker_class_name = nil)
29
- all(worker_class_name).map(&:worker)
30
- end
31
-
32
22
  #
33
23
  # Run all Tasks in the queue. Optionally filter which tasks to run based
34
24
  # on the worker class name.
@@ -116,11 +106,12 @@ module Cloudtasker
116
106
  # @param [Hash] http_request The HTTP request content.
117
107
  # @param [Integer] schedule_time When to run the task (Unix timestamp)
118
108
  #
119
- def initialize(id:, http_request:, schedule_time: nil, queue: nil)
109
+ def initialize(id:, http_request:, schedule_time: nil, queue: nil, job_retries: 0)
120
110
  @id = id
121
111
  @http_request = http_request
122
112
  @schedule_time = Time.at(schedule_time || 0)
123
113
  @queue = queue
114
+ @job_retries = job_retries || 0
124
115
  end
125
116
 
126
117
  #
@@ -155,26 +146,20 @@ module Cloudtasker
155
146
  }
156
147
  end
157
148
 
158
- #
159
- # Return the worker attached to this task.
160
- #
161
- # @return [Cloudtasker::Worker] The task worker.
162
- #
163
- def worker
164
- @worker ||= Worker.from_hash(payload)
165
- end
166
-
167
149
  #
168
150
  # Execute the task.
169
151
  #
170
152
  # @return [Any] The return value of the worker perform method.
171
153
  #
172
154
  def execute
173
- resp = worker.execute
155
+ # Execute worker
156
+ resp = WorkerHandler.with_worker_handling(payload, &:execute)
157
+
158
+ # Delete task
174
159
  self.class.delete(id)
175
160
  resp
176
161
  rescue StandardError
177
- worker.job_retries += 1
162
+ self.job_retries += 1
178
163
  end
179
164
 
180
165
  #
@@ -5,7 +5,7 @@ require 'logger'
5
5
  module Cloudtasker
6
6
  # Holds cloudtasker configuration. See Cloudtasker#configure
7
7
  class Config
8
- attr_accessor :redis
8
+ attr_accessor :redis, :store_payloads_in_redis
9
9
  attr_writer :secret, :gcp_location_id, :gcp_project_id,
10
10
  :gcp_queue_prefix, :processor_path, :logger, :mode, :max_retries
11
11
 
@@ -54,6 +54,21 @@ module Cloudtasker
54
54
  Please specify a secret in the cloudtasker initializer or add Rails secret_key_base in your credentials
55
55
  DOC
56
56
 
57
+ #
58
+ # Return the threshold above which job arguments must be stored
59
+ # in Redis instead of being sent to the backend as part of the job
60
+ # payload.
61
+ #
62
+ # Return nil if redis payload storage is disabled.
63
+ #
64
+ # @return [Integer, nil] The threshold above which payloads will be stored in Redis.
65
+ #
66
+ def redis_payload_storage_threshold
67
+ return nil unless store_payloads_in_redis
68
+
69
+ store_payloads_in_redis.respond_to?(:to_i) ? store_payloads_in_redis.to_i : 0
70
+ end
71
+
57
72
  #
58
73
  # The number of times jobs will be retried. This number of
59
74
  # retries does not include failures due to the application being unreachable.
@@ -114,10 +114,10 @@ module Cloudtasker
114
114
  #
115
115
  # Return all jobs related to this worker class.
116
116
  #
117
- # @return [Array<Cloudtasker::Worker] The list of workers
117
+ # @return [Array<Cloudtasker::Backend::MemoryTask>] The list of tasks
118
118
  #
119
119
  def jobs
120
- Backend::MemoryTask.jobs(to_s)
120
+ Backend::MemoryTask.all(to_s)
121
121
  end
122
122
 
123
123
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cloudtasker
4
- VERSION = '0.9.5'
4
+ VERSION = '0.10.rc1'
5
5
  end
@@ -10,16 +10,113 @@ module Cloudtasker
10
10
  # Alrogith used to sign the verification token
11
11
  JWT_ALG = 'HS256'
12
12
 
13
+ # Sub-namespace to use for redis keys when storing
14
+ # payloads in Redis
15
+ REDIS_PAYLOAD_NAMESPACE = 'payload'
16
+
17
+ # Arg payload cache keys get expired instead of deleted
18
+ # in case jobs are re-processed due to connection interruption
19
+ # (job is successful but Cloud Task considers it as failed due
20
+ # to network interruption)
21
+ ARGS_PAYLOAD_CLEANUP_TTL = 3600 # 1 hour
22
+
23
+ #
24
+ # Return a namespaced key
25
+ #
26
+ # @param [String, Symbol] val The key to namespace
27
+ #
28
+ # @return [String] The namespaced key.
29
+ #
30
+ def self.key(val)
31
+ return nil if val.nil?
32
+
33
+ [to_s.underscore, val.to_s].join('/')
34
+ end
35
+
36
+ #
37
+ # Return the cloudtasker redis client
38
+ #
39
+ # @return [Cloudtasker::RedisClient] The cloudtasker redis client.
40
+ #
41
+ def self.redis
42
+ @redis ||= begin
43
+ require 'cloudtasker/redis_client'
44
+ RedisClient.new
45
+ end
46
+ end
47
+
13
48
  #
14
49
  # Execute a task worker from a task payload
15
50
  #
16
- # @param [Hash] payload The Cloud Task payload.
51
+ # @param [Hash] input_payload The Cloud Task payload.
17
52
  #
18
53
  # @return [Any] The return value of the worker perform method.
19
54
  #
20
- def self.execute_from_payload!(payload)
55
+ def self.execute_from_payload!(input_payload)
56
+ with_worker_handling(input_payload, &:execute)
57
+ end
58
+
59
+ # TODO: do not delete redis payload if job has been re-enqueued
60
+ # worker.job_reenqueued
61
+ #
62
+ # Idea: change with_worker_handling to with_worker_handling and build the worker
63
+ # inside the with_worker_handling block.
64
+ #
65
+ # Local middleware used to retrieve the job arg payload from cache
66
+ # if a arg payload reference is present.
67
+ #
68
+ # @param [Hash] payload The full job payload
69
+ #
70
+ # @yield [Hash] The actual payload to use to process the job.
71
+ #
72
+ # @return [Any] The block result
73
+ #
74
+ def self.with_worker_handling(input_payload)
75
+ # Extract payload information
76
+ extracted_payload = extract_payload(input_payload)
77
+ payload = extracted_payload[:payload]
78
+ args_payload_key = extracted_payload[:args_payload_key]
79
+
80
+ # Build worker
21
81
  worker = Cloudtasker::Worker.from_hash(payload) || raise(InvalidWorkerError)
22
- worker.execute
82
+
83
+ # Yied worker
84
+ resp = yield(worker)
85
+
86
+ # Schedule args payload deletion after job has been successfully processed
87
+ # Note: we expire the key instead of deleting it immediately in case the job
88
+ # succeeds but is considered as failed by Cloud Task due to network interruption.
89
+ # In such case the job is likely to be re-processed soon after.
90
+ redis.expire(args_payload_key, ARGS_PAYLOAD_CLEANUP_TTL) if args_payload_key && !worker.job_reenqueued
91
+
92
+ resp
93
+ rescue DeadWorkerError => e
94
+ # Delete stored args payload if job is dead
95
+ redis.expire(args_payload_key, ARGS_PAYLOAD_CLEANUP_TTL) if args_payload_key
96
+ raise(e)
97
+ end
98
+
99
+ #
100
+ # Return the argument payload key (if present) along with the actual worker payload.
101
+ #
102
+ # If the payload was stored in Redis then retrieve it.
103
+ #
104
+ # @return [Hash] Hash
105
+ #
106
+ def self.extract_payload(input_payload)
107
+ # Get references
108
+ payload = JSON.parse(input_payload.to_json, symbolize_names: true)
109
+ args_payload_id = payload.delete(:job_args_payload_id)
110
+ args_payload_key = args_payload_id ? key([REDIS_PAYLOAD_NAMESPACE, args_payload_id].join('/')) : nil
111
+
112
+ # Retrieve the actual worker args payload
113
+ args_payload = args_payload_key ? redis.fetch(args_payload_key) : payload[:job_args]
114
+
115
+ # Return the payload
116
+ {
117
+ args_payload_key: args_payload_key,
118
+ payload: payload.merge(job_args: args_payload)
119
+ }
23
120
  end
24
121
 
25
122
  #
@@ -51,6 +148,47 @@ module Cloudtasker
51
148
  }
52
149
  end
53
150
 
151
+ #
152
+ # Return true if the worker args must be stored in Redis.
153
+ #
154
+ # @return [Boolean] True if the payload must be stored in redis.
155
+ #
156
+ def store_payload_in_redis?
157
+ Cloudtasker.config.redis_payload_storage_threshold &&
158
+ worker.job_args.to_json.bytesize > (Cloudtasker.config.redis_payload_storage_threshold * 1024)
159
+ end
160
+
161
+ #
162
+ # Return the payload to use for job arguments. This payload
163
+ # is merged inside the #worker_payload.
164
+ #
165
+ # If the argument payload must be stored in Redis then returns:
166
+ # `{ job_args_payload_id: <worker_id> }`
167
+ #
168
+ # If the argument payload must be natively handled by the backend
169
+ # then returns:
170
+ # `{ job_args: [...] }`
171
+ #
172
+ # @return [Hash] The worker args payload.
173
+ #
174
+ def worker_args_payload
175
+ @worker_args_payload ||= begin
176
+ if store_payload_in_redis?
177
+ # Store payload in Redis
178
+ self.class.redis.write(
179
+ self.class.key([REDIS_PAYLOAD_NAMESPACE, worker.job_id].join('/')),
180
+ worker.job_args
181
+ )
182
+
183
+ # Return reference to args payload
184
+ { job_args_payload_id: worker.job_id }
185
+ else
186
+ # Return regular job args payload
187
+ { job_args: worker.job_args }
188
+ end
189
+ end
190
+ end
191
+
54
192
  #
55
193
  # Return the task payload that Google Task will eventually
56
194
  # send to the job processor.
@@ -68,9 +206,8 @@ module Cloudtasker
68
206
  worker: worker.job_class_name,
69
207
  job_queue: worker.job_queue,
70
208
  job_id: worker.job_id,
71
- job_args: worker.job_args,
72
209
  job_meta: worker.job_meta.to_h
73
- }
210
+ }.merge(worker_args_payload)
74
211
  end
75
212
 
76
213
  #
@@ -141,8 +141,7 @@ module Cloudtasker
141
141
  # @param [Proc] &block Optional context block.
142
142
  #
143
143
  def log_message(level, msg, &block)
144
- # Merge log-specific context into worker-specific context
145
- payload_block = ->(*_args) { log_block.call.merge(block&.call || {}) }
144
+ payload_block = block || log_block
146
145
 
147
146
  # ActiveSupport::Logger does not support passing a payload through a block on top
148
147
  # of a message.
data/lib/cloudtasker.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_support/core_ext/string/inflections'
4
- require 'active_support/core_ext/object/try'
5
4
 
6
5
  require 'cloudtasker/version'
7
6
  require 'cloudtasker/config'