Errors

One error class, what it carries, and branching on it with pattern matching.

One rescue covers everything the gem raises:

begin
  channel.publish('status', payload)
rescue Blackevin::Error => error
  error.status_code   # 403, 429, … or nil when no response arrived
  error.reason        # 'queue_limit', 'connection_limit', 'message_rate_limit', or nil
  error.quota?        # a plan ceiling — show an upgrade prompt, retry later
  error.message       # the server's own sentence
end

Branch on status_code and reason. The message is written for a person, and its wording can change.

The three classes

whenretry?
Blackevin::Errorthe node answered with a refusaldepends on the status
Blackevin::ConnectionErrorno response: DNS, refused, TLS, timeoutyes
Blackevin::ConfigurationErrora missing or malformed key, a bad argument — raised before any requestno, fix the call

The last two inherit from the first.

The statuses worth handling

statusmeaning
401unknown, revoked or malformed credentials — or a token request whose MAC, timestamp or nonce was refused
403the key or token does not hold this operation on this channel
404no such queue or rule in this account
429a plan ceiling. Always carries reason

A 429 is not a 403 on purpose: retrying can succeed, because a slot frees or a plan is upgraded.

Pattern matching

Errors, token requests and every returned value implement deconstruct_keys, so a rescue can branch by shape:

rescue Blackevin::Error => error
  case error
  in {reason: 'queue_limit'} then redirect_to upgrade_path
  in {status_code: 401 | 403} then raise
  in {status_code: nil} then retry_job wait: 30.seconds
  end

Secrets stay out of logs

inspect on a key, a client or a token never prints the secret or the token, so an error report that captures local variables does not leak one.

On this page