Ruby on Rails (Rails, RoR) is a well-known web application framework written in the Ruby programming language. Pub/Sub is a short name of software design patterns called Publish–subscribe. I'll explain how communication between software components in Rails could be handled by Pub/Sub.
What is Pub/sub?
Pub/sub is a software design pattern providing service-to-service communication. Service
entails one of the two roles: publisher (who produce) or receiver (who consumes). What is
produced to be consumed is determined as an event or a message or a notification. In the
context of this article, they are used interchangeably to refer to the same thing.
The service which produces doesn't know who consumes. The service which consumes doesn't
know the origin of the message. They can remain unknown to each other. It is different from
message queues, where the component that sends the message often knows its destination
– this style of messaging allows you to send messages anywhere. This mechanism is a core
of Pub/sub and it means that they are decoupled.
To express their mutual interests, they must share a common understanding. Therefore,
both roles have an implicit mechanism of the stick where the producer of a message and the
consumer of the message meet. This mechanism is called subject, subscription or topic. It is
responsible for categorizing messages to subjects, it is essentially a stateless message filter.
Topics act as broadcast stations. A publisher produces the message to the topic,
subscribers immediately receive the message from the topic. Because of decoupled
services, the most efficient way of exchanging messages is to handle them asynchronously.
Rails without Pub/Sub
By default, there is no Rails overhead for software design patterns for passing messages between components. Developers use standard object-oriented programming (OOP) paradigm: passing parameters to functions, asking for classes about values.
When the application is rather uncomplicated, it could be enough. When the application grows, for instance, some operations need to be done asynchronously, then the project needs abstraction which resolves that data workflow. Instead of reinventing the wheel, developers can implement Pub/sub to fill this lack of abstraction.
Pros of Pub/Sub with Rails
- Avoid Active Record Callbacks.
- By adding asynchronous parallel processing to a system, performance, reliability and scalability are improved.
- Messages can be broadcast asynchronously to different parts of the system.
- Allows for messages to be broadcast asynchronously to different parts of a system.
- Decoupling – adding or changing a functionality won't impact anything because Pub/Sub
allows you to modify how everything interacts.
- The message consumer will no longer need to periodically check for updates or new
information. It reduces the delivery latency that can be particularly problematic in systems
with no tolerance for delays.
- There is no limit to how many subscribers the system can handle because it can change,
upgrade, multiply, or disappear at any time.
Cons of Pub/Sub with Rails
- The major disadvantage of Pub/sub systems is their decoupling of publisher and
Rails Pub/Sub introduce
Examples of source in Rails was written using library
Pub/Sub on Rails (in Ruby’s nomenclature, a library is called gem): You will find more details in the gem’s readme. Implementation is composed of modules:
- Event handler,
- Event publisher,
Describes business logic in order to provide context for Pub/Sub and, therefore, make clean code.
It is a class which describes what happened. Declare the class name as self-describing with what happened as possible, for example: cancelled, changed, created, destroyed, sent, updated. Event names can look like: ProfitAndLossStatementCreatedEvent, which means that a financial statement was created.
class Reports::ProfitAndLossStatementCreatedEvent < PubSub::DomainEvent
attribute :profit_and_loss_statement_id, Types::Strict::Integer
Class capable of emitting events. The example shows creating a service report. When the report was successfully created, emit the event of creating that report.
emit(:report_profit_and_loss_statement_created, profit_and_loss_statement_id: id) if result.ok?
This class should be executed in response to handling an event.
class ReportsProfitAndLossStatementCreatedHandler < PubSub::DomainEventHandler
Events are bonded to their handlers through subscriptions.
Example use cases:
- "Follow" feature in social networks,
- Internet of Things,
- Notification about generated files.
- EventBus - components can send events to EventBus without knowing who will pick them up or how many respondents will react,
- Observer – the subject maintains a list of dependents, called observers, and notifies them whenever their state changes,
- Pooling – when polling, clients periodically ask the system whether there are any new events or data.
Pub/sub is not a common approach in Ruby in Rails. As introduced in the article, this pattern can bring many benefits to the project – it can make the code clean, decouple services and make them easily scalable.