patient_http-solid_queue 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,40 +3,43 @@
3
3
  require "patient_http"
4
4
  require "solid_queue"
5
5
 
6
- # Main module for the Solid Queue Async HTTP gem.
7
- #
8
- # This gem provides a mechanism to offload long-running HTTP requests from Solid Queue workers
9
- # to a dedicated async I/O processor running in the same process, freeing worker threads
10
- # immediately while HTTP requests are in flight.
11
- #
12
- # == Usage
13
- #
14
- # request = PatientHttp::Request.new(:get, "https://api.example.com/users/123")
15
- # PatientHttp::SolidQueue.execute(
16
- # request,
17
- # callback: MyCallback,
18
- # callback_args: {user_id: 123}
19
- # )
20
- #
21
- # Define a callback service class with +on_complete+ and +on_error+ methods:
22
- #
23
- # class MyCallback
24
- # def on_complete(response)
25
- # user_id = response.callback_args[:user_id]
26
- # User.find(user_id).update!(data: response.json)
27
- # end
28
- #
29
- # def on_error(error)
30
- # Rails.logger.error("Request failed: #{error.message}")
31
- # end
32
- # end
33
6
  module PatientHttp
7
+ # Runs HTTP requests from Solid Queue jobs on an async I/O processor.
8
+ #
9
+ # The processor runs in the Solid Queue worker process. Worker threads hand
10
+ # off long-running HTTP requests to it and are free to run other jobs while
11
+ # the requests are in flight.
12
+ #
13
+ # This module manages the processors for the current process. It starts one
14
+ # processor for each configured processor profile when a Solid Queue worker
15
+ # starts, and stops them when the worker stops. All processors in a process
16
+ # share one crash-recovery monitor.
17
+ #
18
+ # @example Make a request
19
+ # PatientHttp.get(
20
+ # "https://api.example.com/users/123",
21
+ # callback: MyCallback,
22
+ # callback_args: {user_id: 123}
23
+ # )
24
+ #
25
+ # @example Define a callback service
26
+ # class MyCallback
27
+ # def on_complete(response)
28
+ # user_id = response.callback_args[:user_id]
29
+ # User.find(user_id).update!(data: response.json)
30
+ # end
31
+ #
32
+ # def on_error(error)
33
+ # Rails.logger.error("Request failed: #{error.message}")
34
+ # end
35
+ # end
34
36
  module SolidQueue
37
+ # The gem version.
35
38
  VERSION = File.read(File.join(__dir__, "../../VERSION")).strip
36
39
 
37
- # Raised when the crash-recovery registry entry for a request cannot be
38
- # written. The request is rejected rather than accepted without a durable
39
- # record, and the job retries.
40
+ # Raised when the crash recovery registry entry for a request can't be
41
+ # written. The processor rejects the request instead of accepting it
42
+ # without a durable record, and the job retries.
40
43
  class RegistrationError < StandardError; end
41
44
 
42
45
  autoload :CallbackJob, File.join(__dir__, "solid_queue/callback_job")
@@ -55,7 +58,6 @@ module PatientHttp
55
58
  autoload :TaskMonitorThread, File.join(__dir__, "solid_queue/task_monitor_thread")
56
59
 
57
60
  @processors = {}
58
- @configuration = nil
59
61
  @after_completion_callbacks = []
60
62
  @after_error_callbacks = []
61
63
  @external_storage = nil
@@ -65,105 +67,185 @@ module PatientHttp
65
67
  @monitor_thread = nil
66
68
 
67
69
  class << self
68
- attr_writer :configuration
70
+ # Sets the configuration. Intended for tests.
71
+ #
72
+ # `PatientHttp` stores the configuration, so this method assigns it there.
73
+ #
74
+ # @param config [Configuration, nil] The configuration, or `nil` to build a
75
+ # new one on next use.
76
+ # @return [void]
77
+ def configuration=(config)
78
+ PatientHttp.default_configuration = config
79
+ end
69
80
 
70
- # Configure the gem with a block. The built configuration is also set as the
71
- # `PatientHttp.default_configuration` so that secrets registered at the module
72
- # level with `PatientHttp.register_secret` are applied to the configuration the
73
- # processor runs with, regardless of boot order.
81
+ # Yields the configuration to a block.
82
+ #
83
+ # Every call yields the same configuration object, so options accumulate.
84
+ # Several initializers can each set options without overwriting one
85
+ # another. `PatientHttp.configure` calls this method, so application code
86
+ # can use either one.
74
87
  #
75
- # @yield [Configuration] the configuration object
76
- # @return [Configuration]
88
+ # Configure the gem before the processors start. Running processors use
89
+ # this same configuration object, so an option changed while they run
90
+ # takes effect partway through the requests they're handling, and a
91
+ # processor profile declared while they run isn't started until the
92
+ # next restart. Changing the configuration while processors run logs a
93
+ # warning.
94
+ #
95
+ # @example
96
+ # PatientHttp.configure do |config|
97
+ # config.max_connections = 512
98
+ # end
99
+ #
100
+ # @yield [config] The block that sets configuration options.
101
+ # @yieldparam config [Configuration] The configuration.
102
+ # @return [Configuration] The configuration.
77
103
  def configure
78
- configuration = Configuration.new
79
- yield(configuration) if block_given?
80
- @configuration = configuration
81
- @external_storage = nil
82
- register_handler
83
- PatientHttp.default_configuration = configuration
84
- configuration
104
+ config = configuration
105
+ if block_given?
106
+ if running?
107
+ config.logger&.warn(
108
+ "[PatientHttp::SolidQueue] Configuration changed while processors are running; " \
109
+ "configure the gem before the Solid Queue worker starts."
110
+ )
111
+ end
112
+ yield(config)
113
+ end
114
+ config
85
115
  end
86
116
 
87
- # Return the current configuration, initializing with defaults if necessary.
117
+ # Returns the configuration for this process, and creates it on first use.
88
118
  #
89
- # @return [Configuration]
119
+ # `PatientHttp` stores the configuration, so this method and
120
+ # `PatientHttp.configuration` return the same object. As a result, secrets
121
+ # registered with `PatientHttp.register_secret` reach the configuration
122
+ # that the processors use, regardless of load order.
123
+ #
124
+ # @return [Configuration] The configuration.
90
125
  def configuration
91
- @configuration ||= Configuration.new
126
+ PatientHttp.configuration
127
+ end
128
+
129
+ # Builds a new configuration. `PatientHttp` calls this method when it
130
+ # creates the configuration for this process.
131
+ #
132
+ # @return [Configuration] The new configuration.
133
+ # @api private
134
+ def new_configuration
135
+ Configuration.new
92
136
  end
93
137
 
94
- # Reset configuration to defaults (useful for testing).
138
+ # Resets the configuration to the defaults. Intended for tests.
95
139
  #
96
- # @return [Configuration]
140
+ # @return [Configuration] The new configuration.
97
141
  def reset_configuration!
98
- @configuration = nil
99
- @external_storage = nil
142
+ PatientHttp.default_configuration = nil
100
143
  configuration
101
144
  end
102
145
 
103
- # Add a callback to be executed after a successful request completion.
146
+ # Registers a block to run after each request completes. Use it for
147
+ # monitoring. Blocks run in the order they're registered.
148
+ #
149
+ # @example
150
+ # PatientHttp::SolidQueue.after_completion do |response|
151
+ # StatsD.timing("patient_http.duration", response.duration * 1000)
152
+ # end
104
153
  #
105
- # @yield [response] block to execute after an HTTP request completes
106
- # @yieldparam response [PatientHttp::Response] the HTTP response
154
+ # @yield [response] The block to run.
155
+ # @yieldparam response [PatientHttp::Response] The HTTP response.
156
+ # @return [void]
107
157
  def after_completion(&block)
108
158
  @after_completion_callbacks << block
109
159
  end
110
160
 
111
- # Add a callback to be executed after a request error.
161
+ # Registers a block to run after each request error. Use it for
162
+ # monitoring. Blocks run in the order they're registered.
163
+ #
164
+ # @example
165
+ # PatientHttp::SolidQueue.after_error do |error|
166
+ # StatsD.increment("patient_http.error.#{error.error_type}")
167
+ # end
112
168
  #
113
- # @yield [error] block to execute after an HTTP request errors
114
- # @yieldparam error [PatientHttp::Error] information about the error
169
+ # @yield [error] The block to run.
170
+ # @yieldparam error [PatientHttp::Error] The error.
171
+ # @return [void]
115
172
  def after_error(&block)
116
173
  @after_error_callbacks << block
117
174
  end
118
175
 
119
- # Check if any processor is running.
176
+ # Returns whether any processor is running.
120
177
  #
121
- # @return [Boolean]
178
+ # @return [Boolean] `true` if any processor is running.
122
179
  def running?
123
180
  @processors.values.any?(&:running?)
124
181
  end
125
182
 
126
- # Check if any processor is draining (not accepting new requests).
183
+ # Returns whether any processor is draining. A draining processor doesn't
184
+ # accept new requests but continues to run in-flight requests.
127
185
  #
128
- # @return [Boolean]
186
+ # @return [Boolean] `true` if any processor is draining.
129
187
  def draining?
130
188
  @processors.values.any?(&:draining?)
131
189
  end
132
190
 
133
- # Check if any processor is stopping.
191
+ # Returns whether any processor is stopping.
134
192
  #
135
- # @return [Boolean]
193
+ # @return [Boolean] `true` if any processor is stopping.
136
194
  def stopping?
137
195
  @processors.values.any?(&:stopping?)
138
196
  end
139
197
 
140
- # Check if all processors are stopped or none have been started.
198
+ # Returns whether all processors are stopped.
141
199
  #
142
- # @return [Boolean]
200
+ # @return [Boolean] `true` if all processors are stopped or none has
201
+ # started.
143
202
  def stopped?
144
203
  @processors.values.all?(&:stopped?)
145
204
  end
146
205
 
147
- # Get an ExternalStorage instance for storing and fetching payloads.
206
+ # Returns the external storage for request and result payloads. The
207
+ # storage is rebuilt when the configuration is replaced.
148
208
  #
149
- # @return [PatientHttp::ExternalStorage]
209
+ # @return [PatientHttp::ExternalStorage] The external storage.
150
210
  # @api private
151
211
  def external_storage
152
- @external_storage ||= PatientHttp::ExternalStorage.new(configuration)
212
+ config = configuration
213
+ storage = @external_storage
214
+ unless storage&.config.equal?(config)
215
+ storage = PatientHttp::ExternalStorage.new(config)
216
+ @external_storage = storage
217
+ end
218
+ storage
153
219
  end
154
220
 
155
- # Execute an async HTTP request.
156
- #
157
- # @param request [PatientHttp::Request] the HTTP request to execute
158
- # @param callback [Class, String] Callback service class with +on_complete+ and +on_error+
159
- # instance methods, or its fully qualified class name.
160
- # @param callback_args [#to_h, nil] Arguments to pass to callback
161
- # @param raise_error_responses [Boolean] If true, treats non-2xx responses as errors
162
- # @param processor [Symbol, String, nil] Name of the processor profile that should
163
- # execute the request. Defaults to the request's own processor name or :default.
164
- # @return [String] the request ID
165
- # @raise [PatientHttp::UnknownProcessorError] if the processor profile is not configured
166
- def execute(request, callback:, callback_args: nil, raise_error_responses: false, processor: nil)
221
+ # Runs an HTTP request asynchronously and calls the callback service with
222
+ # the result.
223
+ #
224
+ # Application code normally uses the `PatientHttp` module methods instead,
225
+ # such as `PatientHttp.get`, `PatientHttp.post`, or the
226
+ # PatientHttp::RequestHelper mixin. Those methods take the same options and
227
+ # keep application code independent of the job system. They call this
228
+ # method through the registered request handler.
229
+ #
230
+ # @param request [PatientHttp::Request] The HTTP request.
231
+ # @param callback [Class, String] The callback service class, or its fully
232
+ # qualified name. The class must define `on_complete` and `on_error`
233
+ # instance methods.
234
+ # @param callback_args [#to_h, nil] The arguments to pass to the callback.
235
+ # Values must be JSON-native types: `nil`, `true`, `false`, String,
236
+ # Integer, Float, Array, or Hash. Hash keys are converted to strings. The
237
+ # callback reads the arguments from `response.callback_args` or
238
+ # `error.callback_args` with symbol or string keys.
239
+ # @param raise_error_responses [Boolean, nil] Whether to treat non-2xx
240
+ # responses as errors and call `on_error` instead of `on_complete`. If
241
+ # `nil`, uses the `raise_error_responses` configuration option.
242
+ # @param processor [Symbol, String, nil] The name of the processor profile
243
+ # that runs the request. If `nil`, uses the processor set on the request,
244
+ # then `:default`.
245
+ # @return [String] The request ID.
246
+ # @raise [PatientHttp::UnknownProcessorError] If the processor profile
247
+ # isn't configured.
248
+ def execute(request, callback:, callback_args: nil, raise_error_responses: nil, processor: nil)
167
249
  PatientHttp::CallbackValidator.validate!(callback)
168
250
  callback_name = callback.is_a?(Class) ? callback.name : callback.to_s
169
251
  callback_args = PatientHttp::CallbackValidator.validate_callback_args(callback_args)
@@ -173,14 +255,19 @@ module PatientHttp
173
255
  # Catch a misspelled profile name at the call site. A job that names an
174
256
  # unconfigured profile is retried instead, which covers rolling deploys
175
257
  # where the executing process is older than the enqueueing one.
176
- unless configuration.processor_profiles.key?(processor_name.to_sym)
258
+ profile_config = processor_config_for(processor_name)
259
+ unless profile_config
177
260
  raise PatientHttp::UnknownProcessorError.new("No processor profile configured for #{processor_name.inspect}")
178
261
  end
179
262
 
263
+ # The PatientHttp module methods pass nil when the caller did not ask for a
264
+ # specific behavior, so fall back to the processor profile's setting.
265
+ raise_error_responses = profile_config.raise_error_responses if raise_error_responses.nil?
266
+
180
267
  encrypted = encrypt(request.as_json)
181
268
 
182
269
  data = if external_storage.enabled?
183
- external_storage.store(encrypted, max_size: configuration.payload_store_threshold)
270
+ external_storage.store(encrypted, max_size: profile_config.payload_store_threshold)
184
271
  else
185
272
  encrypted
186
273
  end
@@ -190,8 +277,9 @@ module PatientHttp
190
277
  request_id
191
278
  end
192
279
 
193
- # Start a processor for each configured processor profile, along with
194
- # the shared crash-recovery monitor.
280
+ # Starts a processor for each configured processor profile. Also starts
281
+ # the crash-recovery monitor that the processors share. The Solid Queue
282
+ # lifecycle hooks call this method when a Solid Queue worker starts.
195
283
  #
196
284
  # @return [void]
197
285
  def start
@@ -226,7 +314,8 @@ module PatientHttp
226
314
  register_handler
227
315
  end
228
316
 
229
- # Signal all processors to drain (stop accepting new requests).
317
+ # Drains all processors. A draining processor doesn't accept new requests
318
+ # but continues to run in-flight requests.
230
319
  #
231
320
  # @return [void]
232
321
  def quiet
@@ -237,14 +326,12 @@ module PatientHttp
237
326
  end
238
327
  end
239
328
 
240
- # Stop all processors gracefully.
329
+ # Stops all processors and the services they share. The Solid Queue
330
+ # lifecycle hooks call this method when a Solid Queue worker stops.
241
331
  #
242
- # The request handler stays registered. SolidQueue runs its worker stop hooks
243
- # before the execution pool is drained, and a job that submits a request after
244
- # the processors have stopped must have it enqueued as a job for the next
245
- # process rather than raise. Only {.reset!} removes the handler.
246
- #
247
- # @param timeout [Float, nil] maximum time to wait for in-flight requests to complete
332
+ # @param timeout [Float, nil] The maximum number of seconds to wait for
333
+ # in-flight requests to finish. If `nil`, uses the `shutdown_timeout`
334
+ # configuration option.
248
335
  # @return [void]
249
336
  def stop(timeout: nil)
250
337
  @lifecycle_mutex.synchronize do
@@ -256,27 +343,32 @@ module PatientHttp
256
343
  end
257
344
  end
258
345
 
259
- # Reset all state (useful for testing).
346
+ # Stops all processors and resets all state. Intended for tests.
260
347
  #
261
348
  # @return [void]
262
349
  # @api private
263
350
  def reset!
264
- if @request_handler
265
- PatientHttp.unregister_handler(@request_handler)
266
- end
267
351
  @lifecycle_mutex.synchronize do
268
352
  stop_processors(timeout: 0)
269
353
  @processors = {}
270
354
  shutdown_shared_services
271
355
  end
272
- @configuration = nil
273
356
  @external_storage = nil
274
357
  @after_completion_callbacks = []
275
358
  @after_error_callbacks = []
359
+ PatientHttp.default_configuration = nil
360
+ # Restore the state a freshly loaded process is in: the handler is
361
+ # registered, the configuration is not built yet.
362
+ register_handler
276
363
  end
277
364
 
278
- # Register SolidQueue as the request handler for processing HTTP requests. This is called
279
- # automatically when the processor starts or you call PatientHttp::SolidQueue.configure.
365
+ # Registers this gem as the request handler for `PatientHttp`.
366
+ #
367
+ # The gem calls this method when it loads. As a result, the `PatientHttp`
368
+ # module methods work in every process that loads the gem, whether or not
369
+ # the process runs a processor. The handler stays registered for the life
370
+ # of the process. After the processors stop, requests are enqueued in the
371
+ # queue database for another process to run.
280
372
  #
281
373
  # @return [void]
282
374
  def register_handler
@@ -292,9 +384,9 @@ module PatientHttp
292
384
  PatientHttp.register_handler(@request_handler)
293
385
  end
294
386
 
295
- # Invoke the registered completion callbacks.
387
+ # Calls the blocks registered with {after_completion}.
296
388
  #
297
- # @param response [PatientHttp::Response] the HTTP response
389
+ # @param response [PatientHttp::Response] The HTTP response.
298
390
  # @return [void]
299
391
  # @api private
300
392
  def invoke_completion_callbacks(response)
@@ -305,9 +397,9 @@ module PatientHttp
305
397
  end
306
398
  end
307
399
 
308
- # Invoke the registered error callbacks.
400
+ # Calls the blocks registered with {after_error}.
309
401
  #
310
- # @param error [PatientHttp::Error] information about the error
402
+ # @param error [PatientHttp::Error] The error.
311
403
  # @return [void]
312
404
  # @api private
313
405
  def invoke_error_callbacks(error)
@@ -318,34 +410,41 @@ module PatientHttp
318
410
  end
319
411
  end
320
412
 
321
- # Encrypt a value using the configured encryptor.
413
+ # Encrypts data with the configured encryptor.
322
414
  #
323
- # @param value [Object] the value to encrypt
324
- # @return [String] the encrypted value
415
+ # @param value [Hash] The data to encrypt.
416
+ # @return [Hash] The encrypted data, or the original data if encryption
417
+ # isn't configured.
418
+ # @api private
325
419
  def encrypt(value)
326
420
  configuration.encryptor.encrypt(value)
327
421
  end
328
422
 
329
- # Decrypt a value using the configured encryptor.
423
+ # Decrypts data with the configured encryptor.
330
424
  #
331
- # @param value [String] the encrypted value to decrypt
332
- # @return [Object] the decrypted value
425
+ # @param value [Hash] The data to decrypt.
426
+ # @return [Hash] The decrypted data, or the original data if it isn't
427
+ # encrypted.
428
+ # @api private
333
429
  def decrypt(value)
334
430
  configuration.encryptor.decrypt(value)
335
431
  end
336
432
 
337
- # Returns a processor instance by name (internal accessor).
433
+ # Returns the processor with the given name.
338
434
  #
339
- # @param name [Symbol, String] the processor name
340
- # @return [PatientHttp::Processor, nil]
435
+ # @param name [Symbol, String] The processor name.
436
+ # @return [PatientHttp::Processor, nil] The processor, or `nil` if no
437
+ # processor has that name.
341
438
  # @api private
342
439
  def processor(name = :default)
343
440
  @processors[name.to_sym]
344
441
  end
345
442
 
346
- # Set the default processor (internal, for testing).
443
+ # Sets the default processor. Intended for tests.
347
444
  #
348
- # @param value [PatientHttp::Processor, nil]
445
+ # @param value [PatientHttp::Processor, nil] The processor, or `nil` to
446
+ # remove it.
447
+ # @return [void]
349
448
  # @api private
350
449
  def processor=(value)
351
450
  if value.nil?
@@ -355,24 +454,67 @@ module PatientHttp
355
454
  end
356
455
  end
357
456
 
457
+ # Returns the configuration for a processor profile. Uses the running
458
+ # processor's configuration if there is one.
459
+ #
460
+ # @param name [Symbol, String] The processor name.
461
+ # @return [PatientHttp::Configuration, nil] The configuration for the
462
+ # profile, or `nil` if no processor has that name and the profile isn't
463
+ # declared.
464
+ # @api private
465
+ def processor_config_for(name)
466
+ key = name.to_s
467
+ return nil if key.empty?
468
+
469
+ running = @processors[key.to_sym]
470
+ return running.config if running
471
+
472
+ config = configuration
473
+ config.processor_config(key) if config.processor_options(key)
474
+ end
475
+
358
476
  private
359
477
 
360
- # Stop every processor, draining them at the same time so the timeout
361
- # bounds the whole shutdown instead of each processor in turn.
478
+ # Stops every processor.
479
+ #
480
+ # Each processor waits up to the full timeout for its in-flight requests,
481
+ # so the processors stop in parallel. Stopping them one at a time would
482
+ # multiply the shutdown time by the number of processors. An error from
483
+ # one processor is logged so that the other processors and the shared
484
+ # services still shut down.
485
+ #
486
+ # @param timeout [Float, nil] The maximum number of seconds to wait for
487
+ # in-flight requests.
488
+ # @return [void]
362
489
  def stop_processors(timeout:)
363
490
  processors = @processors.values
364
491
  return if processors.empty?
365
492
 
366
493
  if processors.one?
367
- processors.first.stop(timeout: timeout)
494
+ stop_processor(processors.first, timeout)
368
495
  else
369
- processors.map { |processor| Thread.new { processor.stop(timeout: timeout) } }.each(&:join)
496
+ processors.map { |processor| Thread.new { stop_processor(processor, timeout) } }.each(&:join)
370
497
  end
371
498
  end
372
499
 
373
- # Stop the shared monitor thread and remove this process from the
374
- # registry. Called with the lifecycle mutex held after all processors
375
- # have stopped.
500
+ # Stops a processor and logs any error instead of raising it.
501
+ #
502
+ # @param processor [PatientHttp::Processor] The processor.
503
+ # @param timeout [Float, nil] The maximum number of seconds to wait for
504
+ # in-flight requests.
505
+ # @return [void]
506
+ def stop_processor(processor, timeout)
507
+ processor.stop(timeout: timeout)
508
+ rescue => e
509
+ configuration.logger&.error(
510
+ "[PatientHttp::SolidQueue] Failed to stop processor #{processor.name}: #{e.inspect}"
511
+ )
512
+ end
513
+
514
+ # Stops the monitor thread and removes this process from the registry. The
515
+ # caller must hold the lifecycle mutex and must stop all processors first.
516
+ #
517
+ # @return [void]
376
518
  def shutdown_shared_services
377
519
  @monitor_thread&.stop
378
520
  @monitor_thread = nil
@@ -391,4 +533,14 @@ if defined?(::Rails::Engine)
391
533
  require_relative "solid_queue/engine"
392
534
  end
393
535
 
536
+ # Wire the gem up as soon as it is loaded so that no setup step is required to
537
+ # start making requests:
538
+ #
539
+ # - the request handler is registered, so PatientHttp.get and friends work in
540
+ # every process that requires the gem, configured or not;
541
+ # - PatientHttp.configure and PatientHttp.configuration resolve to this gem's
542
+ # configuration, so applications never have to name the integration;
543
+ # - the Solid Queue lifecycle hooks start and stop the processor with the worker.
544
+ PatientHttp::SolidQueue.register_handler
545
+ PatientHttp.register_configuration_provider(PatientHttp::SolidQueue)
394
546
  PatientHttp::SolidQueue::LifecycleHooks.register
@@ -35,8 +35,8 @@ Gem::Specification.new do |spec|
35
35
 
36
36
  spec.require_paths = ["lib"]
37
37
 
38
- spec.required_ruby_version = ">= 3.2"
38
+ spec.required_ruby_version = ">= 3.3"
39
39
 
40
- spec.add_dependency "patient_http", ">= 1.5.0"
40
+ spec.add_dependency "patient_http", ">= 1.7.0"
41
41
  spec.add_dependency "solid_queue", ">= 1.0.0"
42
42
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: patient_http-solid_queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 1.5.0
18
+ version: 1.7.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 1.5.0
25
+ version: 1.7.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: solid_queue
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -48,7 +48,9 @@ files:
48
48
  - MIT-LICENSE
49
49
  - README.md
50
50
  - VERSION
51
- - db/migrate/20260216000000_create_solid_queue_async_http_tables.rb
51
+ - db/migrate/20260216000000_create_patient_http_solid_queue_tables.rb
52
+ - lib/generators/patient_http/solid_queue/install_generator.rb
53
+ - lib/generators/patient_http/solid_queue/templates/initializer.rb
52
54
  - lib/patient_http-solid_queue.rb
53
55
  - lib/patient_http/solid_queue.rb
54
56
  - lib/patient_http/solid_queue/callback_job.rb
@@ -82,14 +84,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
82
84
  requirements:
83
85
  - - ">="
84
86
  - !ruby/object:Gem::Version
85
- version: '3.2'
87
+ version: '3.3'
86
88
  required_rubygems_version: !ruby/object:Gem::Requirement
87
89
  requirements:
88
90
  - - ">="
89
91
  - !ruby/object:Gem::Version
90
92
  version: '0'
91
93
  requirements: []
92
- rubygems_version: 3.6.9
94
+ rubygems_version: 4.0.3
93
95
  specification_version: 4
94
96
  summary: Offload async HTTP requests from Solid Queue workers to a dedicated async
95
97
  I/O processor