Module: PaymentKit::Instrumentation

Defined in:
lib/payment_kit/instrumentation.rb

Overview

Optional hooks around outbound HTTP requests.

Deliberately separate from the webhook event bus: instrumenting API calls through ActiveSupport::Notifications under the payment_kit. namespace would deliver them to PaymentKit.all webhook subscribers.

PaymentKit::Instrumentation.subscribe(:request_end) do |event|
StatsD.timing("payment_kit.request", event.duration * 1000,
              tags: ["path:#{event.path}", "status:#{event.status}"])
end

Subscriber exceptions are never allowed to break the API call.

Defined Under Namespace

Classes: RequestBeginEvent, RequestEvent

Constant Summary collapse

TOPICS =

Topics that may be subscribed to.

%i[request_begin request_end].freeze

Class Method Summary collapse

Class Method Details

.notify(topic, event) ⇒ Object

Notifies subscribers. A raising subscriber must never break the API call, so failures are swallowed after being reported to $stderr.



95
96
97
98
99
100
101
# File 'lib/payment_kit/instrumentation.rb', line 95

def notify(topic, event)
  subscribers[topic].each_value do |subscriber|
    subscriber.call(event)
  rescue StandardError => e
    warn("[PaymentKit::Instrumentation] #{topic} subscriber raised: #{e.message}")
  end
end

.reset!Object

Drops every subscriber. Intended for test suites.



104
105
106
# File 'lib/payment_kit/instrumentation.rb', line 104

def reset!
  @subscribers = nil
end

.subscribe(topic, name = SecureRandom.uuid, &block) ⇒ Object

Registers block for topic, which must be :request_begin or :request_end. Returns the subscriber name, for use with #unsubscribe.

Raises:

  • (ArgumentError)


74
75
76
77
78
79
80
# File 'lib/payment_kit/instrumentation.rb', line 74

def subscribe(topic, name = SecureRandom.uuid, &block)
  raise ArgumentError, "unknown topic: #{topic}" unless TOPICS.include?(topic)
  raise ArgumentError, "subscriber block required" if block.nil?

  subscribers[topic][name] = block
  name
end

.subscribersObject

Registered blocks, keyed by topic and then by subscriber name.



68
69
70
# File 'lib/payment_kit/instrumentation.rb', line 68

def subscribers
  @subscribers ||= Hash.new { |hash, key| hash[key] = {} }
end

.subscribers?(topic) ⇒ Boolean

Whether topic has any subscribers. The client checks this before building event objects, so an unsubscribed topic costs nothing.

Returns:

  • (Boolean)


89
90
91
# File 'lib/payment_kit/instrumentation.rb', line 89

def subscribers?(topic)
  !subscribers[topic].empty?
end

.unsubscribe(topic, name) ⇒ Object

Removes the subscriber registered under name for topic.



83
84
85
# File 'lib/payment_kit/instrumentation.rb', line 83

def unsubscribe(topic, name)
  subscribers[topic].delete(name)
end