Skip to content

fix(mailing-list): report Flodesk failures to Rollbar, drop dead subscribed? - #2958

Merged
mroderick merged 3 commits into
codebar:masterfrom
costajohnt:fix/2946-report-mailing-list-failures
Sep 28, 2026
Merged

mroderick merged 3 commits into
codebar:masterfrom
costajohnt:fix/2946-report-mailing-list-failures

Conversation

@costajohnt

Copy link
Copy Markdown
Contributor

Closes #2946

Flodesk failures on subscribe/unsubscribe are now reported to Rollbar with the list id and email, and still swallowed so the async job doesn't re-fail. Services::MailingList#subscribed? and Flodesk::Client#subscribed? (plus the ACTIVE constant only they used) are removed with their specs.

Two things turned out different from the issue's plan:

  • Rollbar.error instead of Rails.error.report. rollbar 3.8.0 ships its Rails error subscriber disabled (enable_rails_error_subscriber defaults to false) and config/initializers/rollbar.rb doesn't turn it on, so Rails.error.report never reaches Rollbar in this app. This uses Rollbar.error(e, list_id:, email:) like InvitationManager does. (The same applies to the Rails.error.report in ApplicationJob; that one only surfaces because it re-raises. Happy to switch both over by enabling the subscriber instead if you'd prefer, but that also changes how Rollbar captures uncaught exceptions app-wide, so I left it out of this PR.)
  • Flodesk::Client#request now raises FlodeskError instead of returning it. It rescued Faraday::Error and returned the error object, so the rescue Flodesk::FlodeskError in MailingList never ran for API errors (the only code that looked at the returned error was subscribed?). Timeouts and connection failures also crashed with a NoMethodError because they have no response body; the message now falls back to the Faraday error's. Every caller goes through Services::MailingList, which rescues it. One behaviour change to be aware of: a timeout or connection failure used to crash the job with that NoMethodError, so Delayed Job retried it (up to max_attempts = 3). Now it's reported and swallowed like any other Flodesk failure, per the "keep swallowing" policy in the issue, which means a single network blip can drop a subscribe or unsubscribe. If you'd rather keep those retries, I can swallow only 4xx responses and re-raise timeouts and 5xx so Delayed Job retries them; say the word and I'll push that.

The email address goes into the Rollbar context as the issue asks; Rollbar person tracking already sends member emails with request errors here, so it isn't a new kind of data, but say if you'd rather send the member id.

Testing

  • New client specs with the real raise_error + json middleware: a 503 raises FlodeskError with the API's message and status; a timeout raises FlodeskError
  • New Services::MailingList specs: a failed subscribe/unsubscribe calls Rollbar.error with the list id and email and doesn't raise
  • bundle exec rspec spec/lib spec/services spec/controllers/member spec/features/subscribing_to_newsletter_spec.rb spec/features/manage_contact_preferences_spec.rb: 249 examples, 0 failures; rubocop clean

@mroderick mroderick left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed and verified in a worktree of the PR branch:

  • The diagnosed bug is real: the client's Faraday connection uses response :raise_error, so the old rescue Faraday::Error clause returned a FlodeskError instead of raising — Services::MailingList's rescue Flodesk::FlodeskError never fired, and a 503 left subscribe/unsubscribe returning a truthy error object silently. The old client spec only tested 200 responses, so the failure path was untested.
  • The timeout account is accurate: old code called e.response_body['message'] unguarded, Faraday::TimeoutError has a nil body → NoMethodError → DelayedJob retry (max_attempts = 3 in config/initializers/delayed_job.rb).
  • The Rollbar.error choice is justified: rollbar 3.8.0 ships enable_rails_error_subscriber defaulting to false (verified in the installed gem's lib/rollbar/configuration.rb:108), and config/initializers/rollbar.rb doesn't enable it, so Rails.error.report never reaches Rollbar here. The call matches the InvitationManager precedent.
  • No leftover references to subscribed? or Flodesk::ACTIVE; no caller consumes the subscribe/unsubscribe return value.
  • Ran the PR's exact suite (spec/lib spec/services spec/controllers/member plus both feature specs): 249 examples, 0 failures. rubocop on both changed lib files: clean.

On the flagged behaviour change (a network blip now drops a sync after one attempt instead of being retried 3× by accident): I agree with the choice made here. Re-raising timeouts would end in the DelayedJob failure path, whose Rails.error.report is dead in this app, so the final failure would be invisible outside the DJ table. Every failure visible in Rollbar beats silent retries that can still exhaust. If Flodesk reliability becomes a real problem, re-raising 5xx/timeouts plus enabling the error subscriber is the follow-up, not this PR.

@mroderick
mroderick enabled auto-merge September 28, 2026 06:23
@mroderick
mroderick merged commit b1c57d9 into codebar:master Sep 28, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Surface Services::MailingList failures to Rollbar; delete dead subscribed?

2 participants