Class: Philiprehberger::WebhookBuilder::Client
- Inherits:
-
Object
- Object
- Philiprehberger::WebhookBuilder::Client
- Defined in:
- lib/philiprehberger/webhook_builder/client.rb
Overview
Webhook delivery client with HMAC signing, retry, and tracking.
Instance Attribute Summary collapse
-
#concurrency ⇒ Integer
readonly
The maximum number of concurrent batch deliveries.
-
#default_headers ⇒ Hash
readonly
Default headers included in every delivery.
-
#max_retries ⇒ Integer
readonly
The maximum number of delivery attempts.
-
#timeout ⇒ Integer
readonly
The HTTP timeout in seconds.
-
#url ⇒ String
readonly
The webhook endpoint URL.
Instance Method Summary collapse
-
#deliver(event:, payload:, headers: {}) ⇒ Delivery
Deliver a webhook event.
-
#deliver_batch(events) ⇒ Array<Delivery>
Deliver multiple webhook events concurrently.
-
#initialize(url:, secret:, timeout: 30, max_retries: 3, backoff: :exponential, concurrency: 4, default_headers: {}) ⇒ Client
constructor
Create a new webhook client.
Constructor Details
#initialize(url:, secret:, timeout: 30, max_retries: 3, backoff: :exponential, concurrency: 4, default_headers: {}) ⇒ Client
Create a new webhook client.
37 38 39 40 41 42 43 44 45 46 |
# File 'lib/philiprehberger/webhook_builder/client.rb', line 37 def initialize(url:, secret:, timeout: 30, max_retries: 3, backoff: :exponential, concurrency: 4, default_headers: {}) @url = url @secret = secret @timeout = timeout @max_retries = max_retries @backoff_strategy = Backoff.resolve(backoff) @concurrency = concurrency @default_headers = default_headers.dup.freeze end |
Instance Attribute Details
#concurrency ⇒ Integer (readonly)
Returns the maximum number of concurrent batch deliveries.
23 24 25 |
# File 'lib/philiprehberger/webhook_builder/client.rb', line 23 def concurrency @concurrency end |
#default_headers ⇒ Hash (readonly)
Returns default headers included in every delivery.
26 27 28 |
# File 'lib/philiprehberger/webhook_builder/client.rb', line 26 def default_headers @default_headers end |
#max_retries ⇒ Integer (readonly)
Returns the maximum number of delivery attempts.
20 21 22 |
# File 'lib/philiprehberger/webhook_builder/client.rb', line 20 def max_retries @max_retries end |
#timeout ⇒ Integer (readonly)
Returns the HTTP timeout in seconds.
17 18 19 |
# File 'lib/philiprehberger/webhook_builder/client.rb', line 17 def timeout @timeout end |
#url ⇒ String (readonly)
Returns the webhook endpoint URL.
14 15 16 |
# File 'lib/philiprehberger/webhook_builder/client.rb', line 14 def url @url end |
Instance Method Details
#deliver(event:, payload:, headers: {}) ⇒ Delivery
Deliver a webhook event.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/philiprehberger/webhook_builder/client.rb', line 54 def deliver(event:, payload:, headers: {}) body = JSON.generate({ event: event, payload: payload, timestamp: Time.now.utc.iso8601 }) signature = sign(body) merged_headers = @default_headers.merge(headers) attempts = 0 start_time = monotonic_now last_response_code = nil last_response_body = nil last_error = nil loop do attempts += 1 begin response = send_request(body, signature, event, merged_headers) last_response_code = response.code.to_i last_response_body = response.body if last_response_code >= 200 && last_response_code < 300 return Delivery.new( success: true, response_code: last_response_code, attempts: attempts, duration: monotonic_now - start_time, response_body: last_response_body ) end last_error = "HTTP #{last_response_code}" rescue StandardError => e last_error = e. end break if attempts > @max_retries sleep(@backoff_strategy.call(attempts)) end Delivery.new( success: false, response_code: last_response_code, attempts: attempts, duration: monotonic_now - start_time, response_body: last_response_body, error: last_error ) end |
#deliver_batch(events) ⇒ Array<Delivery>
Deliver multiple webhook events concurrently.
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 132 133 134 135 136 137 138 |
# File 'lib/philiprehberger/webhook_builder/client.rb', line 106 def deliver_batch(events) results = Array.new(events.length) mutex = Mutex.new queue = Queue.new events.each_with_index do |item, index| queue << [item, index] end threads = Array.new([@concurrency, events.length].min) do Thread.new do loop do pair = begin queue.pop(true) rescue ThreadError nil end break unless pair item, index = pair delivery = deliver( event: item[:event], payload: item[:payload], headers: item.fetch(:headers, {}) ) mutex.synchronize { results[index] = delivery } end end end threads.each(&:join) results end |