patient_http 1.6.0 → 1.7.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.
- checksums.yaml +4 -4
- data/ARCHITECTURE.md +8 -7
- data/CHANGELOG.md +39 -0
- data/README.md +540 -514
- data/VERSION +1 -1
- data/lib/patient_http/callback_args.rb +53 -48
- data/lib/patient_http/callback_validator.rb +11 -7
- data/lib/patient_http/class_helper.rb +6 -7
- data/lib/patient_http/client.rb +28 -22
- data/lib/patient_http/client_pool.rb +134 -39
- data/lib/patient_http/completion_executor.rb +20 -20
- data/lib/patient_http/configuration.rb +367 -119
- data/lib/patient_http/connection_endpoint.rb +150 -0
- data/lib/patient_http/encryptor.rb +28 -18
- data/lib/patient_http/error.rb +24 -18
- data/lib/patient_http/external_storage.rb +42 -38
- data/lib/patient_http/http_error.rb +30 -26
- data/lib/patient_http/http_headers.rb +57 -26
- data/lib/patient_http/immediate_retries.rb +98 -0
- data/lib/patient_http/inline_task_handler.rb +15 -10
- data/lib/patient_http/lifecycle_manager.rb +39 -40
- data/lib/patient_http/outgoing_request.rb +25 -23
- data/lib/patient_http/payload.rb +28 -26
- data/lib/patient_http/payload_store/active_record_store.rb +31 -34
- data/lib/patient_http/payload_store/base.rb +42 -46
- data/lib/patient_http/payload_store/file_store.rb +22 -26
- data/lib/patient_http/payload_store/redis_store.rb +28 -34
- data/lib/patient_http/payload_store/s3_store.rb +25 -28
- data/lib/patient_http/payload_store.rb +2 -0
- data/lib/patient_http/processor.rb +111 -79
- data/lib/patient_http/processor_observer.rb +65 -59
- data/lib/patient_http/rails/engine.rb +13 -8
- data/lib/patient_http/redirect_error.rb +50 -41
- data/lib/patient_http/redirect_helper.rb +38 -38
- data/lib/patient_http/request.rb +70 -46
- data/lib/patient_http/request_error.rb +47 -42
- data/lib/patient_http/request_helper.rb +142 -119
- data/lib/patient_http/request_preparer.rb +13 -10
- data/lib/patient_http/request_task.rb +113 -84
- data/lib/patient_http/request_template.rb +87 -64
- data/lib/patient_http/response.rb +58 -52
- data/lib/patient_http/response_reader.rb +66 -65
- data/lib/patient_http/secret_manager.rb +34 -30
- data/lib/patient_http/secret_reference.rb +33 -26
- data/lib/patient_http/synchronous_executor.rb +67 -95
- data/lib/patient_http/task_handler.rb +23 -19
- data/lib/patient_http/time_helper.rb +8 -8
- data/lib/patient_http.rb +311 -186
- data/patient_http.gemspec +3 -2
- metadata +20 -4
|
@@ -8,30 +8,28 @@ end
|
|
|
8
8
|
|
|
9
9
|
module PatientHttp
|
|
10
10
|
module PayloadStore
|
|
11
|
-
#
|
|
11
|
+
# A payload store that keeps payloads as JSON objects in Amazon S3. Use it
|
|
12
|
+
# in production when payloads need durable storage that several processes
|
|
13
|
+
# and hosts share.
|
|
12
14
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# and can be shared across multiple processes/instances.
|
|
15
|
+
# Requires the `aws-sdk-s3` gem. The S3 client is responsible for thread
|
|
16
|
+
# safety.
|
|
16
17
|
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# @example Configuration with S3 bucket
|
|
18
|
+
# @example Register an S3 store
|
|
20
19
|
# s3 = Aws::S3::Resource.new
|
|
21
20
|
# bucket = s3.bucket("my-payloads-bucket")
|
|
22
21
|
# config.register_payload_store(:s3, adapter: :s3, bucket: bucket)
|
|
23
22
|
class S3Store < Base
|
|
24
23
|
Base.register :s3, self
|
|
25
24
|
|
|
26
|
-
# @return [String] The
|
|
25
|
+
# @return [String] The prefix for the keys of all stored payloads.
|
|
27
26
|
attr_reader :key_prefix
|
|
28
27
|
|
|
29
|
-
#
|
|
28
|
+
# Creates an S3 store.
|
|
30
29
|
#
|
|
31
|
-
# @param bucket [Aws::S3::Bucket] S3
|
|
32
|
-
# @param key_prefix [String]
|
|
33
|
-
#
|
|
34
|
-
# @raise [ArgumentError] If bucket is not provided
|
|
30
|
+
# @param bucket [Aws::S3::Bucket] The S3 bucket.
|
|
31
|
+
# @param key_prefix [String] The prefix for all S3 object keys.
|
|
32
|
+
# @raise [ArgumentError] If the bucket is missing.
|
|
35
33
|
def initialize(bucket:, key_prefix: nil)
|
|
36
34
|
raise ArgumentError, "S3 bucket is required" unless bucket
|
|
37
35
|
|
|
@@ -39,21 +37,22 @@ module PatientHttp
|
|
|
39
37
|
@key_prefix = key_prefix || "patient_http/payloads/"
|
|
40
38
|
end
|
|
41
39
|
|
|
42
|
-
#
|
|
40
|
+
# Stores a JSON string in S3.
|
|
43
41
|
#
|
|
44
|
-
# @param key [String]
|
|
45
|
-
#
|
|
46
|
-
# @
|
|
42
|
+
# @param key [String] The unique key. The object key is the key prefix
|
|
43
|
+
# and this key.
|
|
44
|
+
# @param json [String] The serialized JSON.
|
|
45
|
+
# @return [String] The key.
|
|
47
46
|
def store_json(key, json)
|
|
48
47
|
full_key = key_with_prefix(key)
|
|
49
48
|
@bucket.object(full_key).put(body: json, content_type: "application/json")
|
|
50
49
|
key
|
|
51
50
|
end
|
|
52
51
|
|
|
53
|
-
#
|
|
52
|
+
# Fetches stored data.
|
|
54
53
|
#
|
|
55
|
-
# @param key [String] The key
|
|
56
|
-
# @return [Hash, nil] The
|
|
54
|
+
# @param key [String] The key.
|
|
55
|
+
# @return [Hash, nil] The parsed data, or `nil` if the key isn't found.
|
|
57
56
|
def fetch(key)
|
|
58
57
|
full_key = key_with_prefix(key)
|
|
59
58
|
response = @bucket.object(full_key).get
|
|
@@ -63,22 +62,20 @@ module PatientHttp
|
|
|
63
62
|
nil
|
|
64
63
|
end
|
|
65
64
|
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
# Idempotent - does not raise if object doesn't exist.
|
|
65
|
+
# Deletes stored data. Doesn't raise an error if the key doesn't exist.
|
|
69
66
|
#
|
|
70
|
-
# @param key [String] The key
|
|
71
|
-
# @return [Boolean] true
|
|
67
|
+
# @param key [String] The key.
|
|
68
|
+
# @return [Boolean] `true`.
|
|
72
69
|
def delete(key)
|
|
73
70
|
full_key = key_with_prefix(key)
|
|
74
71
|
@bucket.object(full_key).delete
|
|
75
72
|
true
|
|
76
73
|
end
|
|
77
74
|
|
|
78
|
-
#
|
|
75
|
+
# Returns whether a payload exists.
|
|
79
76
|
#
|
|
80
|
-
# @param key [String] The key
|
|
81
|
-
# @return [Boolean] true if the payload exists
|
|
77
|
+
# @param key [String] The key.
|
|
78
|
+
# @return [Boolean] `true` if the payload exists.
|
|
82
79
|
def exists?(key)
|
|
83
80
|
full_key = key_with_prefix(key)
|
|
84
81
|
@bucket.object(full_key).exists?
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module PatientHttp
|
|
4
|
+
# Payload stores for large payloads. Register a store with
|
|
5
|
+
# {Configuration#register_payload_store}.
|
|
4
6
|
module PayloadStore
|
|
5
7
|
autoload :Base, File.join(__dir__, "payload_store/base")
|
|
6
8
|
autoload :ActiveRecordStore, File.join(__dir__, "payload_store/active_record_store")
|
|
@@ -1,40 +1,56 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module PatientHttp
|
|
4
|
-
#
|
|
4
|
+
# Runs HTTP requests in a dedicated reactor thread.
|
|
5
|
+
#
|
|
6
|
+
# The reactor thread uses Ruby's fiber scheduler, so it can run hundreds of
|
|
7
|
+
# requests at the same time. Completion worker threads decode the responses
|
|
8
|
+
# and deliver the results through each task's {TaskHandler}.
|
|
9
|
+
#
|
|
10
|
+
# The processor moves through these states:
|
|
11
|
+
#
|
|
12
|
+
# stopped -> starting -> running -> draining -> stopping -> stopped
|
|
13
|
+
#
|
|
14
|
+
# @example Run a processor
|
|
15
|
+
# config = PatientHttp::Configuration.new(max_connections: 256)
|
|
16
|
+
# processor = PatientHttp::Processor.new(config)
|
|
17
|
+
# processor.start
|
|
18
|
+
# processor.enqueue(task)
|
|
19
|
+
# processor.stop(timeout: 25)
|
|
5
20
|
class Processor
|
|
6
21
|
include TimeHelper
|
|
7
22
|
include RedirectHelper
|
|
8
23
|
|
|
9
|
-
#
|
|
10
|
-
|
|
24
|
+
# The seconds that the reactor waits for a task before it checks for
|
|
25
|
+
# shutdown.
|
|
26
|
+
DEQUEUE_TIMEOUT = 1.0
|
|
11
27
|
|
|
12
|
-
#
|
|
13
|
-
#
|
|
28
|
+
# The base delay in seconds between result delivery attempts. The delay
|
|
29
|
+
# increases linearly with each attempt.
|
|
14
30
|
COMPLETION_RETRY_DELAY = 0.5
|
|
15
31
|
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
32
|
+
# The seconds that the completion workers have to finish at shutdown. The
|
|
33
|
+
# reactor teardown and {#stop} share this time, so the reactor never waits
|
|
34
|
+
# longer than {#stop}.
|
|
19
35
|
COMPLETION_SHUTDOWN_TIMEOUT = 5
|
|
20
36
|
|
|
21
|
-
# @return [Configuration]
|
|
37
|
+
# @return [Configuration] The processor configuration.
|
|
22
38
|
attr_reader :config
|
|
23
39
|
|
|
24
|
-
# @return [String]
|
|
25
|
-
#
|
|
40
|
+
# @return [String] The processor name. Thread names include it, so you can
|
|
41
|
+
# identify the threads of each processor in a process.
|
|
26
42
|
attr_reader :name
|
|
27
43
|
|
|
28
|
-
#
|
|
44
|
+
# A callback that runs after each request. Available only in test mode.
|
|
45
|
+
#
|
|
29
46
|
# @api private
|
|
30
47
|
attr_accessor :testing_callback
|
|
31
48
|
|
|
32
|
-
#
|
|
49
|
+
# Creates a processor.
|
|
33
50
|
#
|
|
34
|
-
# @param config [Configuration]
|
|
35
|
-
# @param name [String, Symbol]
|
|
36
|
-
#
|
|
37
|
-
# @return [void]
|
|
51
|
+
# @param config [Configuration] The processor configuration.
|
|
52
|
+
# @param name [String, Symbol] The processor name. Use a different name for
|
|
53
|
+
# each processor in a process.
|
|
38
54
|
def initialize(config, name: "default")
|
|
39
55
|
@config = config
|
|
40
56
|
@name = name.to_s
|
|
@@ -61,7 +77,7 @@ module PatientHttp
|
|
|
61
77
|
@completion_executor = nil
|
|
62
78
|
end
|
|
63
79
|
|
|
64
|
-
#
|
|
80
|
+
# Starts the processor. This method returns when the reactor is ready.
|
|
65
81
|
#
|
|
66
82
|
# @return [void]
|
|
67
83
|
def start
|
|
@@ -156,9 +172,14 @@ module PatientHttp
|
|
|
156
172
|
observers_to_notify&.each { |observer| notify_observer(observer) { |o| o.start } }
|
|
157
173
|
end
|
|
158
174
|
|
|
159
|
-
#
|
|
175
|
+
# Stops the processor.
|
|
160
176
|
#
|
|
161
|
-
#
|
|
177
|
+
# The processor waits for in-flight requests to finish. When the timeout
|
|
178
|
+
# ends, it calls {TaskHandler#retry} for each request that didn't finish,
|
|
179
|
+
# so the job system can run it again.
|
|
180
|
+
#
|
|
181
|
+
# @param timeout [Numeric, nil] The seconds to wait for in-flight requests.
|
|
182
|
+
# If `nil`, the configured `shutdown_timeout` applies.
|
|
162
183
|
# @return [void]
|
|
163
184
|
def stop(timeout: nil)
|
|
164
185
|
timeout ||= @config.shutdown_timeout
|
|
@@ -243,7 +264,7 @@ module PatientHttp
|
|
|
243
264
|
notify_observers { |observer| observer.stop } if should_notify_stop
|
|
244
265
|
end
|
|
245
266
|
|
|
246
|
-
#
|
|
267
|
+
# Stops accepting new requests. In-flight requests continue to run.
|
|
247
268
|
#
|
|
248
269
|
# @return [void]
|
|
249
270
|
def drain
|
|
@@ -254,11 +275,14 @@ module PatientHttp
|
|
|
254
275
|
@config.logger&.info("[PatientHttp] Processor draining (no longer accepting new requests)")
|
|
255
276
|
end
|
|
256
277
|
|
|
257
|
-
#
|
|
278
|
+
# Adds a task to the processor queue.
|
|
279
|
+
#
|
|
280
|
+
# Observers receive `request_enqueued` before the task is queued. If the
|
|
281
|
+
# processor doesn't accept the task, they receive `request_rejected`.
|
|
258
282
|
#
|
|
259
|
-
# @param task [RequestTask]
|
|
260
|
-
# @raise [NotRunningError]
|
|
261
|
-
# @raise [MaxCapacityError]
|
|
283
|
+
# @param task [RequestTask] The task.
|
|
284
|
+
# @raise [NotRunningError] If the processor isn't running.
|
|
285
|
+
# @raise [MaxCapacityError] If the processor is at `max_connections`.
|
|
262
286
|
# @return [void]
|
|
263
287
|
def enqueue(task)
|
|
264
288
|
raise NotRunningError.new("Cannot enqueue request: processor is #{state}") unless running?
|
|
@@ -278,59 +302,61 @@ module PatientHttp
|
|
|
278
302
|
end
|
|
279
303
|
end
|
|
280
304
|
|
|
281
|
-
#
|
|
305
|
+
# Returns the processor state.
|
|
282
306
|
#
|
|
283
|
-
# @return [Symbol]
|
|
307
|
+
# @return [Symbol] `:stopped`, `:starting`, `:running`, `:draining`, or
|
|
308
|
+
# `:stopping`.
|
|
284
309
|
def state
|
|
285
310
|
@lifecycle.state
|
|
286
311
|
end
|
|
287
312
|
|
|
288
|
-
#
|
|
313
|
+
# Returns whether the processor is starting.
|
|
289
314
|
#
|
|
290
|
-
# @return [Boolean]
|
|
315
|
+
# @return [Boolean] `true` if the state is `:starting`.
|
|
291
316
|
def starting?
|
|
292
317
|
@lifecycle.starting?
|
|
293
318
|
end
|
|
294
319
|
|
|
295
|
-
#
|
|
320
|
+
# Returns whether the processor is running and accepts requests.
|
|
296
321
|
#
|
|
297
|
-
# @return [Boolean]
|
|
322
|
+
# @return [Boolean] `true` if the state is `:running`.
|
|
298
323
|
def running?
|
|
299
324
|
@lifecycle.running?
|
|
300
325
|
end
|
|
301
326
|
|
|
302
|
-
#
|
|
327
|
+
# Returns whether the processor is stopped.
|
|
303
328
|
#
|
|
304
|
-
# @return [Boolean]
|
|
329
|
+
# @return [Boolean] `true` if the state is `:stopped`.
|
|
305
330
|
def stopped?
|
|
306
331
|
@lifecycle.stopped?
|
|
307
332
|
end
|
|
308
333
|
|
|
309
|
-
#
|
|
334
|
+
# Returns whether the processor is draining. A draining processor doesn't
|
|
335
|
+
# accept new requests but continues to run in-flight requests.
|
|
310
336
|
#
|
|
311
|
-
# @return [Boolean]
|
|
337
|
+
# @return [Boolean] `true` if the state is `:draining`.
|
|
312
338
|
def draining?
|
|
313
339
|
@lifecycle.draining?
|
|
314
340
|
end
|
|
315
341
|
|
|
316
|
-
#
|
|
342
|
+
# Returns whether the processor is draining and idle.
|
|
317
343
|
#
|
|
318
|
-
# @return [Boolean]
|
|
344
|
+
# @return [Boolean] `true` if the processor is draining and has no requests.
|
|
319
345
|
def drained?
|
|
320
346
|
@lifecycle.draining? && idle?
|
|
321
347
|
end
|
|
322
348
|
|
|
323
|
-
#
|
|
349
|
+
# Returns whether the processor is stopping.
|
|
324
350
|
#
|
|
325
|
-
# @return [Boolean]
|
|
351
|
+
# @return [Boolean] `true` if the state is `:stopping`.
|
|
326
352
|
def stopping?
|
|
327
353
|
@lifecycle.stopping?
|
|
328
354
|
end
|
|
329
355
|
|
|
330
|
-
#
|
|
331
|
-
#
|
|
356
|
+
# Returns whether the processor is idle. An idle processor has no queued
|
|
357
|
+
# or in-flight requests, and no results that wait for delivery.
|
|
332
358
|
#
|
|
333
|
-
# @return [Boolean]
|
|
359
|
+
# @return [Boolean] `true` if the processor is idle.
|
|
334
360
|
def idle?
|
|
335
361
|
executor = @completion_executor
|
|
336
362
|
tracking_empty = @tasks_lock.synchronize do
|
|
@@ -340,13 +366,14 @@ module PatientHttp
|
|
|
340
366
|
tracking_empty && (executor.nil? || executor.idle?)
|
|
341
367
|
end
|
|
342
368
|
|
|
343
|
-
#
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
# {
|
|
347
|
-
#
|
|
369
|
+
# Returns the number of requests that the processor can accept before it
|
|
370
|
+
# reaches `max_connections`.
|
|
371
|
+
#
|
|
372
|
+
# The value is advisory. {#enqueue} makes the final check, so a concurrent
|
|
373
|
+
# enqueue can still raise {MaxCapacityError}. This method doesn't notify
|
|
374
|
+
# observers, so it's a fast check before a costly enqueue.
|
|
348
375
|
#
|
|
349
|
-
# @return [Integer] remaining capacity
|
|
376
|
+
# @return [Integer] The remaining capacity. Never negative.
|
|
350
377
|
def remaining_capacity
|
|
351
378
|
@tasks_lock.synchronize do
|
|
352
379
|
remaining = @config.max_connections - (@queue.size + @pending_tasks.size + @inflight_requests.size)
|
|
@@ -354,58 +381,58 @@ module PatientHttp
|
|
|
354
381
|
end
|
|
355
382
|
end
|
|
356
383
|
|
|
357
|
-
#
|
|
358
|
-
#
|
|
384
|
+
# Returns whether the processor can accept one more request. The value is
|
|
385
|
+
# advisory. See {#remaining_capacity}.
|
|
359
386
|
#
|
|
360
|
-
# @return [Boolean]
|
|
387
|
+
# @return [Boolean] `true` if the processor has capacity.
|
|
361
388
|
def capacity_available?
|
|
362
389
|
remaining_capacity > 0
|
|
363
390
|
end
|
|
364
391
|
|
|
365
|
-
#
|
|
392
|
+
# Returns the number of requests that are running.
|
|
366
393
|
#
|
|
367
|
-
#
|
|
368
|
-
#
|
|
394
|
+
# The count doesn't include queued or pending tasks. For the count that the
|
|
395
|
+
# capacity check uses, see {#total_count}.
|
|
369
396
|
#
|
|
370
|
-
# @return [Integer]
|
|
397
|
+
# @return [Integer] The number of in-flight requests.
|
|
371
398
|
def inflight_count
|
|
372
399
|
@inflight_requests.size
|
|
373
400
|
end
|
|
374
401
|
|
|
375
|
-
#
|
|
376
|
-
#
|
|
377
|
-
# This is the count used by {#enqueue} for capacity enforcement.
|
|
402
|
+
# Returns the number of queued, pending, and in-flight tasks. {#enqueue}
|
|
403
|
+
# compares this count with `max_connections`.
|
|
378
404
|
#
|
|
379
|
-
# @return [Integer]
|
|
405
|
+
# @return [Integer] The number of tasks.
|
|
380
406
|
def total_count
|
|
381
407
|
@tasks_lock.synchronize do
|
|
382
408
|
@queue.size + @pending_tasks.size + @inflight_requests.size
|
|
383
409
|
end
|
|
384
410
|
end
|
|
385
411
|
|
|
386
|
-
#
|
|
412
|
+
# Returns the IDs of the requests that are running.
|
|
387
413
|
#
|
|
388
|
-
# @return [Array<String>]
|
|
414
|
+
# @return [Array<String>] The task IDs.
|
|
389
415
|
def inflight_request_ids
|
|
390
416
|
@tasks_lock.synchronize do
|
|
391
417
|
@inflight_requests.keys
|
|
392
418
|
end
|
|
393
419
|
end
|
|
394
420
|
|
|
395
|
-
#
|
|
396
|
-
#
|
|
397
|
-
# processor
|
|
421
|
+
# Returns the IDs of all queued, pending, and in-flight tasks. Use it to
|
|
422
|
+
# keep durable tracking, such as heartbeats, current for tasks that the
|
|
423
|
+
# processor accepted but didn't start yet.
|
|
398
424
|
#
|
|
399
|
-
# @return [Array<String>]
|
|
425
|
+
# @return [Array<String>] The task IDs.
|
|
400
426
|
def tracked_request_ids
|
|
401
427
|
@tasks_lock.synchronize do
|
|
402
428
|
(@queued_tasks.keys + @pending_tasks.keys + @inflight_requests.keys).uniq
|
|
403
429
|
end
|
|
404
430
|
end
|
|
405
431
|
|
|
406
|
-
#
|
|
432
|
+
# Adds an observer that receives processor events. If the processor is
|
|
433
|
+
# running, the observer receives `start` immediately.
|
|
407
434
|
#
|
|
408
|
-
# @param observer [ProcessorObserver]
|
|
435
|
+
# @param observer [ProcessorObserver] The observer.
|
|
409
436
|
# @return [void]
|
|
410
437
|
def observe(observer)
|
|
411
438
|
notify_start = false
|
|
@@ -423,30 +450,33 @@ module PatientHttp
|
|
|
423
450
|
notify_observer(observer) { |o| o.start } if notify_start
|
|
424
451
|
end
|
|
425
452
|
|
|
426
|
-
#
|
|
453
|
+
# Waits for the processor to start.
|
|
427
454
|
#
|
|
428
|
-
# @param timeout [Numeric] maximum
|
|
429
|
-
# @return [Boolean] true if started, false if
|
|
455
|
+
# @param timeout [Numeric] The maximum seconds to wait.
|
|
456
|
+
# @return [Boolean] `true` if the processor started, or `false` if the
|
|
457
|
+
# timeout ended first.
|
|
430
458
|
# @api private
|
|
431
459
|
def wait_for_running(timeout: 5)
|
|
432
460
|
start
|
|
433
461
|
@lifecycle.wait_for_running(timeout: timeout)
|
|
434
462
|
end
|
|
435
463
|
|
|
436
|
-
#
|
|
437
|
-
#
|
|
464
|
+
# Waits for the queue to be empty and all in-flight requests to finish.
|
|
465
|
+
# Intended for tests.
|
|
438
466
|
#
|
|
439
|
-
# @param timeout [Numeric] maximum
|
|
440
|
-
# @return [Boolean] true if
|
|
467
|
+
# @param timeout [Numeric] The maximum seconds to wait.
|
|
468
|
+
# @return [Boolean] `true` if the processor is idle, or `false` if the
|
|
469
|
+
# timeout ended first.
|
|
441
470
|
# @api private
|
|
442
471
|
def wait_for_idle(timeout: 1)
|
|
443
472
|
@lifecycle.wait_for_condition(timeout: timeout) { idle? }
|
|
444
473
|
end
|
|
445
474
|
|
|
446
|
-
#
|
|
475
|
+
# Waits for a request to start. Intended for tests.
|
|
447
476
|
#
|
|
448
|
-
# @param timeout [Numeric] maximum
|
|
449
|
-
# @return [Boolean] true if a request started
|
|
477
|
+
# @param timeout [Numeric] The maximum seconds to wait.
|
|
478
|
+
# @return [Boolean] `true` if a request started, or `false` if the timeout
|
|
479
|
+
# ended first.
|
|
450
480
|
# @api private
|
|
451
481
|
def wait_for_processing(timeout: 1)
|
|
452
482
|
@lifecycle.wait_for_condition(timeout: timeout) do
|
|
@@ -454,9 +484,11 @@ module PatientHttp
|
|
|
454
484
|
end
|
|
455
485
|
end
|
|
456
486
|
|
|
457
|
-
#
|
|
458
|
-
#
|
|
487
|
+
# Starts the processor, yields to a block, and then stops the processor.
|
|
488
|
+
# Intended for tests.
|
|
459
489
|
#
|
|
490
|
+
# @yield The block to run while the processor runs.
|
|
491
|
+
# @return [void]
|
|
460
492
|
# @api private
|
|
461
493
|
def run
|
|
462
494
|
start
|