philiprehberger-retry_queue 0.2.0 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22b3442db8a011863de798c26bd3d255b65cc355655bc98c7b32f5dc0d233a01
4
- data.tar.gz: 73279504fb90ae3768d615e2e3e1db7df57151946320490856ccb62a98e7a2d3
3
+ metadata.gz: a5c95df7fb98070ed959408d5fce1be2d1b920a800221d831f24214ffe9425d1
4
+ data.tar.gz: d681958fb8eddf3710283315eb52ff81cc13bec03d67c0e72d1199ec5025ec9e
5
5
  SHA512:
6
- metadata.gz: 106135b96e386b6fbda72eb74adba46d85d8e11eb233736a91b8dc2fec4304baa7ce6497f05553c7a9c649ca7a4641131fd1e2d48a072e013a9f2f6c5bbdbf4e
7
- data.tar.gz: e478bba48e5c678502099b50db3f61714d3e5873bd5f3b244a0e47ff2a781570a703805449983df313bd4c6f3a3833790fe4e54203b579de7ab3279abbabe500
6
+ metadata.gz: 4b91743778fba30ed468fe23da3157c4df3086a81c5aa1784f5d304a967967ad271e7dd9646a54d75a54379b5123f8589614249c346fa760ccc05111f7e6bdcc
7
+ data.tar.gz: e63ef43720e3915d2942c06fd34e33ca79aabe147b3fc678db7812759c0501e6b660e80e4ae37afcc59ab031f8250e04371766888cd873e2edd7f1dc1f9ae0bf
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] - 2026-04-17
11
+
12
+ ### Added
13
+ - `on_failure:` callback for `process` and `Processor`, invoked with `(item, error)` when an item exhausts retries; hook exceptions are swallowed
14
+
15
+ ## [0.2.1] - 2026-03-31
16
+
17
+ ### Changed
18
+ - Standardize README badges, support section, and license format
19
+
10
20
  ## [0.2.0] - 2026-03-29
11
21
 
12
22
  ### Added
data/README.md CHANGED
@@ -2,12 +2,7 @@
2
2
 
3
3
  [![Tests](https://github.com/philiprehberger/rb-retry-queue/actions/workflows/ci.yml/badge.svg)](https://github.com/philiprehberger/rb-retry-queue/actions/workflows/ci.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/philiprehberger-retry_queue.svg)](https://rubygems.org/gems/philiprehberger-retry_queue)
5
- [![GitHub release](https://img.shields.io/github/v/release/philiprehberger/rb-retry-queue)](https://github.com/philiprehberger/rb-retry-queue/releases)
6
5
  [![Last updated](https://img.shields.io/github/last-commit/philiprehberger/rb-retry-queue)](https://github.com/philiprehberger/rb-retry-queue/commits/main)
7
- [![License](https://img.shields.io/github/license/philiprehberger/rb-retry-queue)](LICENSE)
8
- [![Bug Reports](https://img.shields.io/github/issues/philiprehberger/rb-retry-queue/bug)](https://github.com/philiprehberger/rb-retry-queue/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
9
- [![Feature Requests](https://img.shields.io/github/issues/philiprehberger/rb-retry-queue/enhancement)](https://github.com/philiprehberger/rb-retry-queue/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)
10
- [![Sponsor](https://img.shields.io/badge/sponsor-GitHub%20Sponsors-ec6cb9)](https://github.com/sponsors/philiprehberger)
11
6
 
12
7
  Batch processor with per-item retry, backoff, and dead letter collection
13
8
 
@@ -72,6 +67,20 @@ result = Philiprehberger::RetryQueue.process(items, max_retries: 3, on_retry: [l
72
67
  end
73
68
  ```
74
69
 
70
+ ### Dead-letter Notifications
71
+
72
+ ```ruby
73
+ on_failure = ->(item, error) { Rails.logger.error("Dead-lettered #{item}: #{error.message}") }
74
+
75
+ result = Philiprehberger::RetryQueue.process(items, max_retries: 3, on_failure: on_failure) do |item|
76
+ process_item(item)
77
+ end
78
+ ```
79
+
80
+ The hook fires once per item that exhausts its retries, just as the item is recorded in
81
+ `Result#failed`. Exceptions raised inside the hook are swallowed so a faulty callback cannot
82
+ break the queue.
83
+
75
84
  ### DLQ Reprocessing
76
85
 
77
86
  ```ruby
@@ -102,7 +111,8 @@ stats = result.stats
102
111
 
103
112
  | Method | Description |
104
113
  |--------|-------------|
105
- | `.process(items, max_retries:, concurrency:, backoff:, retry_on:, on_retry:) { \|item\| }` | Process items with retry logic |
114
+ | `.process(items, max_retries:, concurrency:, backoff:, retry_on:, on_retry:, on_failure:) { \|item\| }` | Process items with retry logic |
115
+ | `on_failure:` | Callable `(item, error)` invoked once per item that exhausts retries; hook errors are swallowed |
106
116
  | `Result#succeeded` | Array of successfully processed items |
107
117
  | `Result#failed` | Array of hashes with `:item`, `:error`, `:attempts` |
108
118
  | `Result#stats` | Hash with `:total`, `:succeeded`, `:failed`, `:success_rate`, `:elapsed` |
@@ -118,10 +128,21 @@ bundle exec rubocop
118
128
 
119
129
  ## Support
120
130
 
121
- If you find this package useful, consider giving it a star on GitHub — it helps motivate continued maintenance and development.
131
+ If you find this project useful:
132
+
133
+ ⭐ [Star the repo](https://github.com/philiprehberger/rb-retry-queue)
134
+
135
+ 🐛 [Report issues](https://github.com/philiprehberger/rb-retry-queue/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
136
+
137
+ 💡 [Suggest features](https://github.com/philiprehberger/rb-retry-queue/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)
138
+
139
+ ❤️ [Sponsor development](https://github.com/sponsors/philiprehberger)
140
+
141
+ 🌐 [All Open Source Projects](https://philiprehberger.com/open-source-packages)
142
+
143
+ 💻 [GitHub Profile](https://github.com/philiprehberger)
122
144
 
123
- [![LinkedIn](https://img.shields.io/badge/Philip%20Rehberger-LinkedIn-0A66C2?logo=linkedin)](https://www.linkedin.com/in/philiprehberger)
124
- [![More packages](https://img.shields.io/badge/more-open%20source%20packages-blue)](https://philiprehberger.com/open-source-packages)
145
+ 🔗 [LinkedIn Profile](https://www.linkedin.com/in/philiprehberger)
125
146
 
126
147
  ## License
127
148
 
@@ -12,7 +12,10 @@ module Philiprehberger
12
12
  # @param backoff [Proc, nil] proc receiving attempt number, returns sleep duration
13
13
  # @param retry_on [Array<Class>, nil] exception classes to retry on; nil means retry all
14
14
  # @param on_retry [Array<Proc>, Proc, nil] callbacks fired before each retry attempt
15
- def initialize(max_retries: 3, concurrency: 1, backoff: nil, retry_on: nil, on_retry: nil)
15
+ # @param on_failure [Proc, nil] callable invoked with `(item, error)` once per item that
16
+ # exhausts retries and moves to the dead-letter list; exceptions raised by the hook are
17
+ # swallowed so a faulty hook cannot break the queue
18
+ def initialize(max_retries: 3, concurrency: 1, backoff: nil, retry_on: nil, on_retry: nil, on_failure: nil)
16
19
  raise Error, 'max_retries must be non-negative' unless max_retries.is_a?(Integer) && max_retries >= 0
17
20
 
18
21
  @max_retries = max_retries
@@ -20,6 +23,7 @@ module Philiprehberger
20
23
  @backoff = backoff || DEFAULT_BACKOFF
21
24
  @retry_on = retry_on
22
25
  @on_retry_hooks = Array(on_retry)
26
+ @on_failure = on_failure
23
27
  end
24
28
 
25
29
  # Process a collection of items with retry logic.
@@ -54,6 +58,7 @@ module Philiprehberger
54
58
  rescue StandardError => e
55
59
  if !retryable?(e) || attempts > @max_retries
56
60
  failed << { item: item, error: e, attempts: attempts }
61
+ fire_on_failure_hook(item, e)
57
62
  return
58
63
  end
59
64
 
@@ -74,6 +79,16 @@ module Philiprehberger
74
79
  @on_retry_hooks.each { |hook| hook.call(item, error, attempt) }
75
80
  end
76
81
 
82
+ def fire_on_failure_hook(item, error)
83
+ return if @on_failure.nil?
84
+
85
+ @on_failure.call(item, error)
86
+ rescue StandardError
87
+ # Swallow hook errors — this is a best-effort notification and must never
88
+ # break the queue. Intentionally silent; users can log inside their hook.
89
+ nil
90
+ end
91
+
77
92
  def now
78
93
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
79
94
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module RetryQueue
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
@@ -16,15 +16,20 @@ module Philiprehberger
16
16
  # @param backoff [Proc, nil] custom backoff strategy
17
17
  # @param retry_on [Array<Class>, nil] exception classes to retry on; others go straight to failed
18
18
  # @param on_retry [Array<Proc>, nil] callbacks fired before each retry attempt
19
+ # @param on_failure [Proc, nil] callable invoked with `(item, error)` once per item that
20
+ # exhausts retries and moves to the dead-letter list; exceptions raised by the hook are
21
+ # swallowed so a faulty hook cannot break the queue
19
22
  # @yield [item] block that processes a single item
20
23
  # @return [Result] processing result
21
- def self.process(items, max_retries: 3, concurrency: 1, backoff: nil, retry_on: nil, on_retry: nil, &block)
24
+ def self.process(items, max_retries: 3, concurrency: 1, backoff: nil, retry_on: nil, on_retry: nil,
25
+ on_failure: nil, &block)
22
26
  processor = Processor.new(
23
27
  max_retries: max_retries,
24
28
  concurrency: concurrency,
25
29
  backoff: backoff,
26
30
  retry_on: retry_on,
27
- on_retry: on_retry
31
+ on_retry: on_retry,
32
+ on_failure: on_failure
28
33
  )
29
34
  processor.call(items, &block)
30
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-retry_queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
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-30 00:00:00.000000000 Z
11
+ date: 2026-04-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Processes collections of items with configurable per-item retry logic,
14
14
  exponential backoff, and dead letter collection for failed items. Returns detailed
@@ -26,11 +26,11 @@ files:
26
26
  - lib/philiprehberger/retry_queue/processor.rb
27
27
  - lib/philiprehberger/retry_queue/result.rb
28
28
  - lib/philiprehberger/retry_queue/version.rb
29
- homepage: https://github.com/philiprehberger/rb-retry-queue
29
+ homepage: https://philiprehberger.com/open-source-packages/ruby/philiprehberger-retry_queue
30
30
  licenses:
31
31
  - MIT
32
32
  metadata:
33
- homepage_uri: https://github.com/philiprehberger/rb-retry-queue
33
+ homepage_uri: https://philiprehberger.com/open-source-packages/ruby/philiprehberger-retry_queue
34
34
  source_code_uri: https://github.com/philiprehberger/rb-retry-queue
35
35
  changelog_uri: https://github.com/philiprehberger/rb-retry-queue/blob/main/CHANGELOG.md
36
36
  bug_tracker_uri: https://github.com/philiprehberger/rb-retry-queue/issues