Class: Falcon::Limiter::LongTask
- Inherits:
-
Object
- Object
- Falcon::Limiter::LongTask
- Defined in:
- lib/falcon/limiter/long_task.rb
Overview
Manages long-running tasks by releasing connection tokens during I/O operations to prevent contention and maintain server responsiveness.
A long task is any long (1+ sec) operation that isn’t CPU-bound (usually long I/O). Starting a long task lets the server accept one more (potentially CPU-bound) request. This allows us to handle many concurrent I/O bound requests, without adding contention (which impacts latency).
Constant Summary collapse
- STOP_PRIORITY =
The priority to use when stopping a long task to re-acquire the connection token.
1000
Instance Attribute Summary collapse
-
#tags ⇒ Object
readonly
Returns the value of attribute tags.
Class Method Summary collapse
- .current ⇒ Object
-
.current=(long_task) ⇒ Object
Assign the current long task.
-
.for(request, limiter, **options) ⇒ Object
Create a long task for the given request.
Instance Method Summary collapse
-
#acquired? ⇒ Boolean
Check if the long task has been acquired.
-
#initialize(request, limiter, connection_token = nil, start_delay: 0.1) ⇒ LongTask
constructor
Initialize a new long task with the specified configuration.
-
#pending? ⇒ Boolean
Check if the long task is waiting to acquire the long task token.
-
#start(delay: @start_delay, tags: nil) ⇒ Object
Start the long task, optionally with a delay to avoid overhead for short operations.
-
#started? ⇒ Boolean
Check if the long task has been started, but not necessarily acquired (e.g. if there was a delay).
-
#stop(force: false, **options) ⇒ Object
Stop the long task and restore connection token.
-
#with ⇒ Object
Execute the block with the current long task.
Constructor Details
#initialize(request, limiter, connection_token = nil, start_delay: 0.1) ⇒ LongTask
Initialize a new long task with the specified configuration.
60 61 62 63 64 65 66 67 68 69 |
# File 'lib/falcon/limiter/long_task.rb', line 60 def initialize(request, limiter, connection_token = nil, start_delay: 0.1) @request = request @limiter = limiter @connection_token = connection_token @start_delay = start_delay @token = Async::Limiter::Token.new(@limiter) @delayed_start_task = nil @tags = nil end |
Instance Attribute Details
#tags ⇒ Object (readonly)
Returns the value of attribute tags.
22 23 24 |
# File 'lib/falcon/limiter/long_task.rb', line 22 def @tags end |
Class Method Details
.current ⇒ Object
25 26 27 |
# File 'lib/falcon/limiter/long_task.rb', line 25 def self.current Fiber.current.falcon_limiter_long_task end |
.current=(long_task) ⇒ Object
Assign the current long task.
30 31 32 |
# File 'lib/falcon/limiter/long_task.rb', line 30 def self.current=(long_task) Fiber.current.falcon_limiter_long_task = long_task end |
.for(request, limiter, **options) ⇒ Object
Create a long task for the given request. Extracts connection token from the request if available for proper token management.
49 50 51 52 53 54 |
# File 'lib/falcon/limiter/long_task.rb', line 49 def self.for(request, limiter, **) # Get connection token from request if possible: connection_token = request&.connection&.stream&.io&.token rescue nil return new(request, limiter, connection_token, **) end |
Instance Method Details
#acquired? ⇒ Boolean
Check if the long task has been acquired.
79 80 81 |
# File 'lib/falcon/limiter/long_task.rb', line 79 def acquired? @token.acquired? end |
#pending? ⇒ Boolean
Check if the long task is waiting to acquire the long task token.
85 86 87 |
# File 'lib/falcon/limiter/long_task.rb', line 85 def pending? @delayed_start_task != nil end |
#start(delay: @start_delay, tags: nil) ⇒ Object
Start the long task, optionally with a delay to avoid overhead for short operations
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/falcon/limiter/long_task.rb', line 90 def start(delay: @start_delay, tags: nil) # If already started, nothing to do: if started? if block_given? return yield self else return self end end if delay == true delay = @start_delay elsif delay == false delay = nil end @tags = # Otherwise, start the long task: if delay&.positive? # Wait specified delay before starting the long task: @delayed_start_task = Async do sleep(delay) self.acquire rescue Async::Stop # Gracefully exit on stop. ensure @delayed_start_task = nil end else # Start the long task immediately: self.acquire end return self unless block_given? begin yield self ensure self.stop end end |
#started? ⇒ Boolean
Check if the long task has been started, but not necessarily acquired (e.g. if there was a delay).
73 74 75 |
# File 'lib/falcon/limiter/long_task.rb', line 73 def started? @token.acquired? || @delayed_start_task end |
#stop(force: false, **options) ⇒ Object
Stop the long task and restore connection token
134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/falcon/limiter/long_task.rb', line 134 def stop(force: false, **) if delayed_start_task = @delayed_start_task @delayed_start_task = nil delayed_start_task.stop end # Re-acquire the connection token with high priority than inbound requests: [:priority] ||= STOP_PRIORITY # Release the long task token: release(force, **) ensure @tags = nil end |
#with ⇒ Object
Execute the block with the current long task.
35 36 37 38 39 40 41 |
# File 'lib/falcon/limiter/long_task.rb', line 35 def with previous = self.class.current self.class.current = self yield ensure self.class.current = previous end |