Hey!

Hey is a lightweight pubsub wrapper that makes it easy to change underlying messaging implementations and also includes some convenience utilities to:

  • Track a chain of events
  • Sanitize sensitive data from event payloads
  • Set arbitrary data that will be included on every event published on the same thread

Installation

Add this line to your application's Gemfile:

gem 'hey-pubsub', require: 'hey'

And then execute:

$ bundle

Or install it yourself as:

$ gem install hey-pubsub

Why use Hey?

We often treat logging, exception notification and event broadcasting as separate operations within our code. Hey encourages you to treat everything as a published event that is meaningful to the current operation being performed.

Any number of subscribers may react to the event once it's published. For example a published registration failure event could have a logstash subscriber logging the failure details into Kibana and a HoneyBadger subscriber recording the exception and notifying the dev team. A successful registration event, on the other hand, could trigger a welcome email delivery.

The utilities Hey provides, such as data sanitization, makes it more appealing to combine these logging and pubsub use cases. Additionally the ability to switch out messaging implementations means you start with a simple approach (ActiveSupport Notifications) and ease into using a more distributed, asynchronous approach as your application grows without changing your code.

Shared Metadata

Hey provides utilities to share metadata across all events published on the same thread.

Event chain UUID

The first time an event is published via Hey a UUID will be assigned and stored on the current thread.

Any events published for the life of the current thread with include this uuid in their payloads. This allows a chain of events to be associated later in a Kibana dashboard, for example.

This UUID could be used across disparate systems subscribing to the same message bus, so long as the convention is adhered to.

Contexts

Use contexts if you want to attach meta-data to all events that happen on a thread from a certain point forward.

Hey.context(ip_address: "127.0.0.1") do
  Hey.publish!("registration.succeeded", { email: "[email protected]" })
end

The payloads of all events wrapped in a context will include this extra data.

You may also nest contexts:

Hey.context(ip_address: "127.0.0.1") do
  Hey.context(current_actor: "Jack Ship") do
    Hey.publish!("registration.succeeded", { email: "[email protected]" })
  end
end

Sanitizing payloads

There are times you'd like sensitive information to be stripped from event payloads. For example, if you are logging API requests and responses you should redact credentials before writing to a database or logfile.

It's easier to handle this sanitization during publication, since subscribers of the events will likely not know what values to strip. Hey provides a utility to record these sensitive values and every event published within a context and will redact them from their payloads.

You can sanitize data by using the key sanitize in your contexts:

Hey.context(sanitize: ["227-76-1234"]) do
  Hey.publish!("registration.succeeded", { email: "[email protected]" })
end

Namespacing events

You can automatically namespace your event names using contexts and a top-level namespace.

A top-level namespace can be configured like this:

Hey.configure do |config|
  config.global_namespace = “my-app”
end

As can a delimiter for chaining an event name together, the default of which is “:” :

Hey.configure do |config|
  config.delimiter = /
end

With this configuration, an event’s name would look like this:

Hey.publish!("registered", { email: "[email protected]" })
=> "my-app/registered"

You can also set a namespace on contexts and they will automatically be chained together in the order they are nested:

Hey.context(namespace: “foo”) do
  Hey.context(namespace: “bar”) do
    Hey.publish!(“hooray”)
  end
end

=> "foo:bar:hooray"

Event publishing and subscribing

Adapters

Hey uses an ActiveSupport Notifications adapter by default, which is essentially a synchronous event bus. However it is easy to configure a different adapter if needed:

Hey.configure do |config|
  config.pubsub_adapter = FooBar::RabbitMqAdapter
end

Note: Currently the only adapter is the aforementioned Hey::Pubsub::Adapters::AsnAdapter

Publishing

To gain all of the Hey goodness, you have to of course use the Hey publish! method:

Hey.publish!("registration.succeeded", { email: "[email protected]" })

The resulting payload would look something like this:

{
  uuid: "0a5d3f22-2cff-4126-a791-c4ac31a2a5bb",
  current_actor: {
    id: "123343",
    type: "Employee",
    name: "Jack Ship"
  },
  email: "[email protected]"
}

Note: Though ASN supports passing objects in payloads since it's all in the same thread, do not do it. If you ever switch to an asyncronous adapter it will fail. Only pass JSON compatible values.

Subscribing

To subscribe to a published event, do this:

Hey.subscribe!("registration.succeeded") do |payload|
  email = payload["email"]
  RegistrationMailer.new_customer(email).deliver
end

Middleware

A faraday middleware adapter is provided to automatically broadcast all requests and responses.

faraday_connection = ::Faraday.new(url: base_url) do |faraday|
  faraday.use Hey::Pubsub::Middleware::Faraday
  faraday.adapter ::Faraday.default_adapter
end

It will broadcast the event names "request" and "response", so be sure to use contexts and namespacing to make the event names more meaningful.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake rspec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ShippingEasy/hey-pubsub.

License

The gem is available as open source under the terms of the MIT License.