philiprehberger-task_queue 0.2.2 → 0.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dbb261ee851c5f9064db0d79ecf1684ec7134b9df747437279afc27411ac7d40
4
- data.tar.gz: 3b9e9c93835a2e1406d8ac2a153a912c0ce087351e35f9c2c49faf52622e2003
3
+ metadata.gz: '088f95205b874279733ad703f517d81cb5f7694e7fc9ed2248c481869384e423'
4
+ data.tar.gz: 9d3940ad0849cd7ecbeaa7f5cb7afa3c1a19e49d95ce3ca7cd4ce2b23afd4679
5
5
  SHA512:
6
- metadata.gz: b4050c1c34922d3f4c0d155152c5f29e2e612104a56e8af82bbcbbb0bfd7a1a7ba4ab0e6963224e7c79a9aace383bdefa33147eb2e25f8c299d7f10993d10059
7
- data.tar.gz: e94f4f029b34ea77cbd7d7afcf5031cdfdee1935b185e65ae328d3ceae2cb65788bc14736f5a3cbb39c7e479519045b81e6bc753f2e91eaeeab91c0decfe5df3
6
+ metadata.gz: d8043a08aebd40789f3da64d6d88aa65342dee25cbc70aa4cadaae94400a60ba23158fcab58eb822916d04af4ce596645f6b018b57df16b77fef57a7be8b5da7
7
+ data.tar.gz: f4b653d153a61fb6f8126969aa0763e8f0d22c4694dffcb352d82120b53e81a85de924b7ee1b0fc6a1983a7cf60ad0b4035a83513c5344f561dd51b6847ddd65
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.3] - 2026-03-20
4
+
5
+ ### Changed
6
+ - Expand README with detailed API documentation and usage examples
7
+
3
8
  ## 0.2.2
4
9
 
5
10
  - Fix RuboCop Style/StringLiterals violations in gemspec
data/README.md CHANGED
@@ -49,44 +49,100 @@ queue << -> { puts "Hello from a task!" }
49
49
 
50
50
  ### Error handling
51
51
 
52
+ Register a callback to handle exceptions raised inside tasks. The callback receives the exception and the original task (callable) that failed. Unhandled errors are silently swallowed when no callback is registered.
53
+
52
54
  ```ruby
53
- queue = Philiprehberger::TaskQueue.new
55
+ queue = Philiprehberger::TaskQueue.new(concurrency: 2)
54
56
 
55
57
  queue.on_error do |exception, task|
56
- puts "Task failed: #{exception.message}"
58
+ warn "[TaskQueue] #{exception.class}: #{exception.message}"
59
+ warn exception.backtrace.first(5).join("\n")
57
60
  end
58
61
 
59
- queue.push { raise "oops" }
62
+ queue.push { Integer("not_a_number") }
63
+ queue.push { File.read("/nonexistent") }
64
+
65
+ queue.drain(timeout: 5)
66
+ puts queue.stats
67
+ # => { completed: 0, failed: 2, pending: 0 }
60
68
  ```
61
69
 
62
70
  ### Statistics
63
71
 
72
+ `stats` returns a snapshot of completed, failed, and pending counts. All counters are thread-safe and updated atomically after each task finishes.
73
+
64
74
  ```ruby
65
- queue.stats
66
- # => { completed: 5, failed: 1, pending: 2 }
75
+ queue = Philiprehberger::TaskQueue.new(concurrency: 4)
76
+
77
+ 20.times { |i| queue.push { sleep(0.01); raise "boom" if i == 5 } }
78
+ queue.drain(timeout: 10)
79
+
80
+ stats = queue.stats
81
+ puts "Completed: #{stats[:completed]}"
82
+ puts "Failed: #{stats[:failed]}"
83
+ puts "Pending: #{stats[:pending]}"
84
+ # Completed: 19
85
+ # Failed: 1
86
+ # Pending: 0
87
+ ```
88
+
89
+ ### FIFO ordering guarantees
90
+
91
+ Tasks are stored in an internal array and dequeued in FIFO order. When `concurrency` is `1`, tasks execute strictly in the order they were pushed. With higher concurrency, dequeue order is still FIFO but tasks may complete out of order depending on individual execution time.
92
+
93
+ ```ruby
94
+ results = Queue.new # stdlib thread-safe queue for collecting output
95
+ queue = Philiprehberger::TaskQueue.new(concurrency: 1)
96
+
97
+ 5.times { |i| queue.push { results << i } }
98
+ queue.drain(timeout: 5)
99
+
100
+ puts results.size.times.map { results.pop }
101
+ # => [0, 1, 2, 3, 4]
102
+ ```
103
+
104
+ ### Graceful shutdown
105
+
106
+ `shutdown` signals all worker threads to stop accepting new tasks, lets in-flight tasks finish, then drains any remaining enqueued tasks before joining threads. The `timeout` parameter caps total wait time; workers that exceed the deadline are abandoned.
107
+
108
+ ```ruby
109
+ queue = Philiprehberger::TaskQueue.new(concurrency: 4)
110
+
111
+ 100.times { |i| queue.push { sleep(0.05) } }
112
+
113
+ queue.shutdown(timeout: 10)
114
+ puts queue.running? # => false
115
+ # queue.push { ... } would now raise "queue is shut down"
67
116
  ```
68
117
 
69
118
  ### Draining
70
119
 
120
+ `drain` blocks the calling thread until all pending and in-flight tasks finish, but keeps the queue running so new tasks can still be pushed afterwards.
121
+
71
122
  ```ruby
123
+ queue = Philiprehberger::TaskQueue.new(concurrency: 4)
124
+
72
125
  10.times { |i| queue.push { process(i) } }
73
126
  queue.drain(timeout: 10) # waits for all tasks to finish
74
- # queue is still running and accepting new tasks
127
+ puts queue.running? # => true still accepting new tasks
128
+
129
+ queue.push { process(:extra) }
130
+ queue.shutdown(timeout: 5)
75
131
  ```
76
132
 
77
133
  ## API
78
134
 
79
- | Method | Description |
80
- |---|---|
81
- | `.new(concurrency: 4)` | Create a new queue with the given max worker count |
82
- | `#push(&block)` | Enqueue a task (block) for async execution |
83
- | `#<< (&block)` | Alias for `#push` |
84
- | `#size` | Number of pending (not yet started) tasks |
85
- | `#running?` | Whether the queue is accepting new tasks |
86
- | `#shutdown(timeout: 30)` | Gracefully stop all workers, waiting up to `timeout` seconds |
87
- | `#on_error(&block)` | Register error callback for failed tasks |
88
- | `#stats` | Returns hash with `:completed`, `:failed`, `:pending` counts |
89
- | `#drain(timeout: 30)` | Block until all pending tasks complete (without shutdown) |
135
+ | Method | Parameters | Returns | Description |
136
+ |---|---|---|---|
137
+ | `.new(concurrency:)` | `concurrency` — max worker threads (Integer, default `4`) | `Queue` | Create a new queue with the given concurrency limit |
138
+ | `#push(&block)` | `&block` — the task to execute | `self` | Enqueue a block for async execution; raises `ArgumentError` if no block given, raises `RuntimeError` if the queue is shut down |
139
+ | `#<<(callable)` | `callable` — any object responding to `#call` | `self` | Alias for `#push`; convenient for lambdas and procs |
140
+ | `#size` | _(none)_ | `Integer` | Number of pending (not yet started) tasks |
141
+ | `#running?` | _(none)_ | `Boolean` | Whether the queue is accepting new tasks |
142
+ | `#shutdown(timeout:)` | `timeout` — seconds to wait for workers (Numeric, default `30`) | `nil` | Signal workers to stop, drain remaining tasks, join threads up to `timeout` seconds |
143
+ | `#on_error(&block)` | `&block` — callback receiving `(exception, task)` | `self` | Register an error callback invoked when a task raises a `StandardError` |
144
+ | `#stats` | _(none)_ | `Hash` | Returns `{ completed:, failed:, pending: }` with Integer counts |
145
+ | `#drain(timeout:)` | `timeout` — seconds to wait (Numeric, default `30`) | `nil` | Block until all pending and in-flight tasks complete without shutting down |
90
146
 
91
147
 
92
148
  ## Development
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module TaskQueue
5
- VERSION = "0.2.2"
5
+ VERSION = "0.2.3"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-task_queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Rehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-19 00:00:00.000000000 Z
11
+ date: 2026-03-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A lightweight, zero-dependency, thread-safe in-process async job queue
14
14
  with configurable concurrency for Ruby applications.