Default adapter doesn't raise on error?
Closed this issue · 7 comments
While writing a test for an app, I realised that:
stub_request(:post, "https://ssl.google-analytics.com/collect").to_return(status: 500, body: "", headers: {})
would not raise an error.
What would be the best strategy to get an error (to e.g. retry in sidekiq) in case the POST failed? (maybe using a custom adapter?)
Ok I see that writing an adapter is quite easy, so I'll do that.
I wonder if you'd welcome a doc patch to warn that track!
won't raise by default?
Yeah, staccato is a "fire-and-forget" style by default. This mirrors tools that interface with statsd, etc. We didn't want to interrupt an application if google is down, or there is a network issue.
Always happy to take a look at PRs that clarify, thank you!
I'd also be open to making something like this configurable.
Strange though, in reviewing the code, I'm not seeing anywhere that we catch errors. I assume they would just bubble up from the adapter.
What was the adapter you were using? The default net/http? I think that may just return a response with a 500, not raise an error. You might be able to check that response and raise yourself.
Fire-and-forget is good usually for that indeed! Here I'm working in a background job, so I'll prefer to retry later.
Indeed I'm using the default net/http adapter, which won't raise for a 500 (but will for plenty of other cases https://stackoverflow.com/a/5370726/20302).
I'll either handle the response, or will write a quick custom adapter.
Thanks for the quick reply!
@thbar In further thinking about this … I would love to add an adapter for like actionjob or something. I think it could be pretty plug-and-play. Are you using Rails and/or ActiveJob?
@tpitale it's a Rails app. In my case though, I prefer to use Sidekiq than ActiveJob!
FWIW, here is what I came up with, because post_form
does not return the HTTP response:
require 'httparty'
module Custom
module Staccato
class HTTPartyAdapter
attr_reader :uri
def initialize(uri)
@uri = uri
end
def post(data)
HTTParty.post(uri, body: data)
end
end
end
end
Then later in my Sidekiq job, I do:
class GoogleAnalyticsWorker
include Sidekiq::Worker
sidekiq_options retry: false
def perform(options)
hit = Staccato::Event.new(build_tracker,
action: options.fetch('action'),
category: options.fetch('category'),
document_hostname: options.fetch('document_hostname'),
data_source: options.fetch('data_source')
)
hit.add_custom_dimension(1, default_value(options.fetch('foobar_1')))
hit.add_custom_dimension(2, default_value(options.fetch('foobar_2')))
hit.add_custom_dimension(3, default_value(options.fetch('foobar_3')))
response = hit.track!
return if response.success?
raise "Failed to send event to Google Analytics (HTTP #{response.code})"
end
# record with a blank dimension value won't be counted into general reports
def default_value(value)
value.blank? ? 'not provided' : value
end
def build_tracker
Staccato.tracker(ENV.fetch('GA_PROPERTY_ID'), nil, ssl: true) do |c|
c.adapter = Custom::Staccato::HTTPartyAdapter.new(Staccato.ga_collection_uri(true))
end
end
end
This makes sure that whenever the GA response is not in the 2XX range, I'll get an exception.
Interesting, I have been away from the ruby/rails world too long. It seems ActiveJob isn't as popular as just using the background job of your choice. Unnecessary abstraction.