davetron5000 / event_lawyer

Prototype code to explore consumer/producer-driven contracts for messaging systems
6 stars 0 forks source link

event-lawyer - enforcing guarantees and expectations for messaging

A Producer sends messages that others consume. A Consumer consumes that message. To ensure that changes in either don't break the overall system, we can enforce a contract. The Producer provides a guarantee of what it produces. The Consumer publishes an expectation of what it needs.

The guarantees and expectations can be published in a centralized store such that both sides can check that they aren't breaking anything.

WTF is in this repo

This has example code of one producer, ItemPriceUpdater that sends messages on a Rabbit exchange about the change in price of an item. There are two consumers, PriceCacheHandler, which updates a cache of item prices for financial purposes, and PackSlipHandler, which updates packing slips with the updated item prices.

How it works

When you run the test of the producer, it requires a schema for its payload, and writes out the guarantee. When you run the test of a consumer, it grabs that guarantee and feeds an example payload into itself to start the test. It evaluates the payload against it's schema and then writes out an expectation capturing all this. The producer, when the tests are re-run, will grab these expectations and evaluate the sample payloads against it's schema.

Terms

Guarantee

A guarantee consists of three parts:

Expectation

An expectation consists of three parts:

System Components

The system requires three components to work:

Producer Testing Framework

Absent this system, the producer would have a test that asserts it sends a message. The testing framework here would augment that test to produce a guarantee. It must:

It must further, if given an Expectation:

it "sends a message" do
  allow(Pwwka::Transmitter).to receive(:send_message!)

  MyApp.do_stuff!

  expect(Pwwka::Transmitter).to have_received(:send_message!).with(payload)

  guarantee = Guarantee.new(schema: "my_schema.json", id: "My Stuff", metadata: { routing_key: "sf.foo.bar" })
  expect(Pwwka::Transmitter).to have_received(:send_message!).with(provides_guarantee(guarantee))
end

Consumer Testing Framework

Absent this system, the consumer would have a test that when it receives a message, that message triggers some expected code. The testing framework here would:

Further, it must:

it "processes a message" do

end