Skip to content

Add support for custom notifiers#500

Open
gabrieltaylor wants to merge 3 commits intoankane:masterfrom
ritual:add-support-for-custom-notifiers
Open

Add support for custom notifiers#500
gabrieltaylor wants to merge 3 commits intoankane:masterfrom
ritual:add-support-for-custom-notifiers

Conversation

@gabrieltaylor
Copy link

Description

Adds support for sending failing checks to a custom notifier.

Happy to adjust the code however you recommend if this change has value for other users. Happy to close the PR if it doesn't :)

Motivation

In our application we find value in triggering alerts from failing Blazer checks. In order to create alerts in a third party system we need to send a specific payload to that service via an HTTP POST request.

To enable this function we've defined a module that implements:

  • state_change
  • failing_checks

following the pattern defined by the Blazer::EmailNotifier and Blazer::SlackNotifier.

The interface implemented by the module is

  module Interface
    def self.state_change(check:, state:, state_was:, result:, message:, check_type:)
    end

    def self.failing_checks(checks)
    end
  end

The implementation might look something like this

module BlazerService
  module CheckFailureHttpNotifier
    extend T::Sig

    sig { params(check: Blazer::Check, state: String, state_was: String, result: Blazer::Result, message: T.nilable(String), check_type: String).returns(Net::HTTPResponse) }
    def self.state_change(check:, state:, state_was:, result:, message:, check_type:)
      payload = build_payload(check:, state:, state_was:, result:, message:, check_type:)
      make_request(payload)
    end

    sig { params(checks: T::Array[Blazer::Check]).void }
    def self.failing_checks(checks)
      # noop
    end

    sig { params(payload: T::Hash[Symbol, T.untyped]).returns(Net::HTTPResponse) }
    def self.make_request(payload)
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = (uri.scheme == "https")

      request = Net::HTTP::Post.new(uri.request_uri, {"Content-Type" => "application/json", "Accept" => "application/json"})
      request.body = payload.to_json

      http.request(request)
    end

    sig { params(check: Blazer::Check, state: String, state_was: String, result: Blazer::Result, message: T.nilable(String), check_type: String).returns(T::Hash[Symbol, T.untyped]) }
    def self.build_payload(check:, state:, state_was:, result:, message:, check_type:)
      {
        check_id: check.id,
        query_name: check.query&.name,
        query_description: check.query&.description,
        query_statement: check.query&.statement,
        row_count: result.rows.size,
        state:,
        state_was:,
        message:,
        check_type:
      }
    end

    sig { returns(URI::HTTP) }
    def self.uri
      T.cast(URI.parse(url), URI::HTTP)
    end

    sig { returns(String) }
    def self.url
      ENV.fetch("BLAZER_HTTP_NOTIFICATION_URL")
    end
  end
end

We're adding the custom notifier in the initializer like this.

Rails.application.config.to_prepare do
  notifier = BlazerService::CheckFailureHttpNotifier
  unless Blazer.custom_notifiers.include?(notifier)
    Blazer.custom_notifiers << notifier
  end
end

Gabriel Taylor Russ added 3 commits March 26, 2025 16:44
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.

1 participant