Dry-Configurable lazy evaluated default settings

Dry-configurable isĀ  a simple mixin to make Ruby classes configurable. It is quite nice, uses Struct and allows you to have default values. Unfortunately, it does not support (yet hopefully) default values that are evaluated upon each setting key request.

When would that be useful? Let’s take a simple example: Kafka + Zookeeper. Zookeeper stores informations about Kafka cluster. They may vary in time, so unless you take them in real time, you might have problem if the cluster were reconfigured. The best option is to set a proc that will be evaluated on each setting request. This is how to obtain such a behavior (note that this will evaluate only default values – if you assign proc in configure block, it will be returned):

# Patch that will allow to use proc based lazy evaluated settings with Dry Configurable
class Dry::Configurable::Config
  # @param [Array] All arguments that a Struct accepts
  def initialize(*args)
    super
    setup_dynamics
  end

  private

  # Method that sets up all the proc based lazy evaluated dynamic config values
  def setup_dynamics
    self.to_h.each do |key, value|
      next unless value.is_a?(Proc)

      rebuild(key)
    end
  end

  # Method that rebuilds a given accessor, so when it consists a proc value, it will
  # evaluate it upon return
  # @param method_name [Symbol] name of an accessor that we want to rebuild
  def rebuild(method_name)
    metaclass = class << self; self; end

    metaclass.send(:define_method, method_name) do
      super().is_a?(Proc) ? super().call : super()
    end
  end
end

Example usage:

class Application
  extend Dry::Configurable

  setting :standard_setting
  setting :lazy_assigned
  setting :lazy_default, -> { "lazy_default-#{rand}" }

  # Note that this works for nested values as well
  setting :namespaced do
    setting :lazy, -> { "namespaced.lazy-#{rand}" }
  end
end

Application.configure do |config|
  config.standard_setting = 1
  config.lazy_assigned = -> { "lazy_assigned-#{rand}" }
end

Application.config.standard_setting #=> 1
Application.config.standard_setting #=> 1
Application.config.lazy_assigned #=> <Proc>
Application.config.lazy_default #=> "lazy_default-0.9601194173446863"
Application.config.lazy_default #=> "lazy_default-0.9450471949405372"
Application.config.namespaced.lazy #=> "namespaced.lazy-0.6938534114443213"
Application.config.namespaced.lazy #=> "namespaced.lazy-0.747101587617097"
25
May 2016
POSTED BY
POSTED IN Ruby Software
DISCUSSION 0 Comments

Errbit + HTTPS: Setting up Errbit reporter (Airbrake v5 gem) to work with self-signed HTTPS certificate

Note: If you’re using old Errbit version (0.2.0, 0.4.0) and an old Airbrake version (v4) please refer to this manual to make it work with self-signed certificates.

Having an error catcher like Errbit behind SSL is generally a good idea. Especially when Errbit is hosted on a different server than you application (for example when you manage multiple apps with one Errbit instance). In many cases you will have a self-signed certificate (why would you pay for a cert for internal tool). If you try to use it with Airbrake, you will see following error:

Airbrake:
  HTTP error: SSL_connect returned=1 errno=0 state=unknown state: certificate verify failed

Unfortunately, global SSL certificates verification disabling hack (solution that used to work with Airbrake notifier v4) won’t work:

# No longer working!
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

Luckily, Airbrake notifier is written pretty well, so hacking it (and disabling per request SSL certificate verification) is not hard at all. Here’s a full code you need to place in config/initializers/errbit.rb to make it work:

module Patches
  module Airbrake
    module SyncSender
      def build_https(uri)
        super.tap do |req|
          req.verify_mode = OpenSSL::SSL::VERIFY_NONE
        end
      end
    end
  end
end

Airbrake::SyncSender.prepend(::Patches::Airbrake::SyncSender)

After that (and configuring Airbrake notifier), you can test it out like this:

Airbrake.notify :test
10
May 2016
POSTED BY
DISCUSSION 3 Comments