Module: Tina4::Background
- Defined in:
- lib/tina4/background.rb
Overview
Periodic background task registry.
Matches Python's tina4_python.core.server.background(fn, interval) and
PHP's $app->background($callback, $interval) — a callback that runs
periodically alongside the server lifecycle.
Ruby has no asyncio event loop, so each task runs in its own dedicated OS thread, started at registration time. Because the thread runs regardless of which web server (Puma/WEBrick) is in front, a Ruby background task is never a silent no-op under production — the thread IS the runtime (contrast the Python ASGI / PHP-FPM silent-no-op the other frameworks had to fix). The GIL keeps it cooperative-enough for the periodic work this is meant for (queue draining, health checks, simulators). Errors in the callback are caught and logged so they don't kill the thread.
Defined Under Namespace
Classes: Task
Class Method Summary collapse
-
.count ⇒ Integer
Number of REGISTERED background tasks (stopped ones are already gone).
-
.register(callback = nil, interval: 1.0, &block) ⇒ Task
Register a periodic callback.
-
.stop_all(timeout: 2.0) ⇒ Object
Stop and join every running task.
-
.stop_task(task, timeout: 2.0) ⇒ Boolean
Stop a single task and DEREGISTER it.
-
.tasks ⇒ Object
All registered task handles.
Class Method Details
.count ⇒ Integer
Number of REGISTERED background tasks (stopped ones are already gone).
The count half of the ONE shared surface, matching Python's
background_task_count(), PHP's backgroundTaskCount() and Node's
backgroundTaskCount().
107 108 109 |
# File 'lib/tina4/background.rb', line 107 def count mutex.synchronize { tasks.length } end |
.register(callback = nil, interval: 1.0, &block) ⇒ Task
Register a periodic callback.
85 86 87 88 89 90 91 92 93 94 |
# File 'lib/tina4/background.rb', line 85 def register(callback = nil, interval: 1.0, &block) cb = callback || block raise ArgumentError, "background requires a callback or block" if cb.nil? raise ArgumentError, "callback must respond to :call" unless cb.respond_to?(:call) task = Task.new(cb, interval.to_f) mutex.synchronize { tasks << task } start_task(task) task end |
.stop_all(timeout: 2.0) ⇒ Object
Stop and join every running task. Called on graceful shutdown.
Each stop_task deregisters its own handle, so there is no blanket
tasks.clear here: clearing would ALSO drop a task registered while
this loop was running — leaving its thread alive but invisible in the
registry, which is the worse of the two failure modes.
117 118 119 120 |
# File 'lib/tina4/background.rb', line 117 def stop_all(timeout: 2.0) snapshot = mutex.synchronize { tasks.dup } snapshot.each { |task| stop_task(task, timeout: timeout) } end |
.stop_task(task, timeout: 2.0) ⇒ Boolean
Stop a single task and DEREGISTER it. Used by Task#stop, by graceful
shutdown, and by any subsystem that owns a task for part of its life
(e.g. Mqtt::Client#stop_keepalive).
The handle is removed from tasks so the registry never reports a stopped
task as registered — leaving it in place made tasks grow for the life of
the process on every start/stop cycle and made introspection lie about
what is actually running.
Idempotent: a second call on the same handle removes nothing, finds no thread and returns false.
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/tina4/background.rb', line 135 def stop_task(task, timeout: 2.0) task.running = false # Identity, not equality: `tasks.delete(task)` uses `==`, which would take # out any OTHER handle that happens to compare equal. Only this exact one # goes, and we record whether it WAS registered so stop() is a truthful bool. was_registered = mutex.synchronize do present = tasks.any? { |registered| registered.equal?(task) } tasks.delete_if { |registered| registered.equal?(task) } present end thread = task.thread if thread thread.join(timeout) || thread.kill task.thread = nil end was_registered end |
.tasks ⇒ Object
All registered task handles. Tests use this for introspection.
97 98 99 |
# File 'lib/tina4/background.rb', line 97 def tasks @tasks ||= [] end |