GCP Pub/Sub with Ruby on Rails
Streamline cross-component communication in your micro-service architecture
Streamline cross-component communication in your micro-service architecture
TL;DR Checkout Cloudenvoy, a Ruby gem relying on Google Cloud Pub/Sub to greatly simplify cross-component communication.
The purpose of a micro-service or lambda architecture is to break down your platform logic into smaller reusable components which are more maintainable from a code and scalability perspective.
But as you build this type of architecture a few questions start popping up:
In a world where Kubernetes, GCP Cloud Run or AWS Fargate exist, scaling runtimes has never been easier. What remains difficult however is scaling databases, especially relational ones.
Therefore I do not recommend sharing databases between your components as a mean to share contextual data between them because that will make your overall platform hard to scale.
You may expose private APIs on your components that can be queried by other components, but that will make your data flows complicated and introduce a lot of querying logic in your components which will bloat the code.
Instead, make your components listen to data streams and extract/replicate the data in their own datastore. This way you can address scalability problems step by step as they arise.
Our approach at Keypup is the following:
Cross-component communication via API is a fairly straightforward. Use any API standard (jsonapi, GraphQL, custom) and stick to it so that components can invoke functions from other components.
There are two big solutions commonly used nowadays:
In the end the concept is mostly the same for both solutions:
So today I'll write about how to leverage Pub/Sub on Google Cloud Platform to maintain data consistency across your Rails applications.
We at Keypup are heavy users of GCP Pub/Sub and we needed a way to make message publishing and subscribing simple in our applications. So we created Cloudenvoy to do just that.
Cloudenvoy provides Ruby bindings to:
This is what a publisher looks like:
This is what a subscriber looks like:
Let's say you have two Rails applications. The first app is your main platform where users signup. The second one is a communication app sending messages to your users using the most appropriate channel (email, slack, other).
The communication app is invoked by API by the main app every time a message must be sent to a user. Only the user ID is passed as part of that API invocation. This means the communication app must be able to lookup the user context to send the message via the right channel.
First add the gem to both apps and run bundle install:
Then add an initializer to configure Cloudenvoy on each app:
We'll be working locally. So the best is to download the gcloud CLI and install the pub/sub emulator:
That's it. Let's jump into the fun part now.
What we want is publish user attributes every time a user is created/updated/deleted. We'll assume your main app has an ActiveRecord model called User.
Let's create a user publisher. The publisher is responsible for specifying the topic it publishes to as well as formatting the actual message payload:
Now let's modify our User model to call our UserPublisher via callbacks:
Finally ensure the topic is created on pub/sub:
That's it! User updates will now be published to pub/sub every time a user is created/updated/deleted.
What we want here is to upsert a local user every time we receive an update. We'll assume there is an ActiveRecord model called User in this app.
Let's create the subscriber:
Then ensure a subscription is registered in pub/sub:
Finally start your application to listen to pub/sub messages via webhook:
Done! Our communication app will now maintain its list of platform users automatically.
Start a rails console on your main app, create a user and display its id. The action of creating the user will publish an update via pub/sub:
Then start a rails console on your communication app and verify your user is there:
Feel free to update your user in the main app and verify that the user in the second app has been properly updated. I guarantee it works :)
Cloudenvoy never gets more complicated than the example above. Format -> Publish -> Receive -> Process. That's it.
With Cloudenvoy in hand you can start getting rid of all these API endpoints and ruby methods you were using to keep your Rails applications in sync with each other and simplify your data flows a LOT. Data, events, asynchronous actions...you can do them all via Pub/Sub and Cloudenvoy.
Also GCP Pub/Sub will guarantee deliverability, so you don't even need to worry about error handling if one of your components is down. Cross-component communication cannot get any simpler than that.
Keypup's SaaS solution allows engineering teams and all software development stakeholders to gain a better understanding of their engineering efforts by combining real-time insights from their development and project management platforms. The solution integrates multiple data sources into a unified database along with a user-friendly dashboard and insights builder interface. Keypup users can customize tried-and-true templates or create their own reports, insights and dashboards to get a full picture of their development operations at a glance, tailored to their specific needs.
---
Code snippets hosted with ❤ by GitHub.
Banner designed by starline / Freepik