-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Publish lifecycle events to routemaster #19
Conversation
Has an ActiveRecord module, a basic publisher implementation, and a registry for publishers. Still needs a bunch more work, but this should be a slightly cleaner version of what’s in orderweb geared towards more complex publishing and multi-publishing.
module LifecycleEvents | ||
extend ActiveSupport::Concern | ||
|
||
ROUTEMASTER_EVENT_TYPE_MAP = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd add a little comment — this maps ActiveRecord events to Routemaster events?
@@ -0,0 +1,49 @@ | |||
require 'active_support/concern' | |||
require 'new_relic/agent' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing a require for roo_on_rails/routemaster/publishers
which is referenced.
def publish! | ||
return unless publish? | ||
|
||
event_data = data # cache in case it isn't memoised |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
erm, "cache" ? "memoise"? data
is a stub/virtual method so this doesn't actually do anything. I think you could replace lines 18-21 with just:
routemaster.send(event, topic, url, data: recursive_stringify(event_data))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(with a caveat for the nil
case of course)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be fair this pattern is copied from your code ;-)
But yes I did mean memoise. It could be cleaned by handling nil in the stringify method though.
class Publisher | ||
attr_reader :model, :event | ||
|
||
def initialize(model, event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest dependency-injecting a client: ::Routemaster::Client
here — otherwise people are going to stub like hell when testing publisherS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair
@@ -0,0 +1,49 @@ | |||
module RooOnRails |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing a require for routemaster/client
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A series of nitpicks but LGTM. Can't "approve" just yet, of course :P
Seems like a good plan. |
Addresses the review comments and makes things a bit tidier.
@mezis @danielcooper this is going to be "interesting" to test properly as RooOnRails itself isn't a Rails app so doesn't have any database etc. to actually test an ActiveRecord model against. The only thing I really need that for is the |
Can you provide a nice api for doing it, and perhaps a test helper - rather than mocking it out? |
(not that you can test after commit when you've transactional tests anyway) |
Codecov Report
@@ Coverage Diff @@
## master #19 +/- ##
==========================================
+ Coverage 91.26% 91.92% +0.66%
==========================================
Files 75 82 +7
Lines 1958 2131 +173
==========================================
+ Hits 1787 1959 +172
- Misses 171 172 +1
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. This will need some docs both in the README and in code docs I think.
You'll probably want some more eyes too
|
||
module ClassMethods | ||
def publish_lifecycle_events(*events) | ||
events ||= %i(create update destroy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be something along the lines of
events = events.any? ? events : %i(create update destroy)
*events
will produce [] with no arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, described_class._commit_callbacks
will give you a list of registed callbacks. You should use this in your test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, that's super helpful. I'll try that, thank you 🙂
spec/integration/routemaster_spec.rb
Outdated
|
||
it 'inserts Routemaster Client into the middleware stack' do | ||
app.wait_start | ||
expect(output).to include 'Routemaster::Client' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the client have to be in the middleware stack?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added 1 small question.
There are some models (e.g. restaurant) where we don't want to actually delete/destroy the object, so we mark it as deleted in the db.
Would roo_on_rails handle this scenario?
Else nice work!
@client = client | ||
end | ||
|
||
def publish? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this method always return true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intention is that it's ready to be overloaded in the clients own publishers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is that it's true
by default and you can then overwrite this in your implementation. You can see this in the example I provide.
You can either overload the publisher's I suppose it depends on us having a standard gem we use for soft deletes? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, one minor typo
Thanks for thorough the readme on this 👍
README.md
Outdated
* `ROOBUS_URL` – the full URL of your Routemaster application (mandatory) | ||
* `ROOBUS_UUID` – the UUID of your application, e.g. `logistics-dashboard` (mandatory) | ||
|
||
If you then want to enable the publishing of events onto the event but, you need to set `ROUTEMASTER_PUBLISHING_ENABLED` to `true` and implement publishers as needed. An example of how to do this is detailed in [`README.routemaster_client.md`](README.routemaster_client.md). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor typo: but
-> bus
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good spot, thank you!
README.routemaster_client.md
Outdated
include Rails.application.routes.url_helpers | ||
|
||
def publish? | ||
noop? || model.new_record? || model.previous_changes.any? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could always move this into the base implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds reasonable to me 👍
# app/publishers/order_publisher.rb | ||
class OrderPublisher < BasePublisher | ||
def url | ||
api_order_url(model, host: ENV.fetch('API_HOST'), protocol: 'https') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could move this into the base implementation too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, no, this one can't really move into the base implementation because sometimes there's an api_
prefix on the routes, sometimes not, and sometimes it's different. That's why I just raised I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think this one is best to handle in the individual service apps indeed.
end | ||
|
||
def roobus_url | ||
ENV.fetch('ROOBUS_URL') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It strikes me that using ROUTEMASTER_URL and ROUTEMASTER_UUID would probably be cleaner names, but if people are dead set on ROOBUS_ then I guess that's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just assumed that these were prefixed with ROOBUS_
for a good reason and didn't even question it, but it would definitely make sense to be more consistent and use ROUTEMASTER_
. Happy to make this change if people agree.
Note: It looks like it would just leave ROOBUS_CALLBACK_URL
using ROOBUS_
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd prefer ROUTEMASTER_
over ROOBUS_
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM; couple of suggestions about docs that could be moved into the Publisher
class as they look like they're sensible things to have in there anyway, but that could always be done at a later date.
147023b
to
1c207a4
Compare
README.md
Outdated
- [HireFire Workers](#hirefire-workers) | ||
- [Logging](#logging) | ||
- [Google Oauth](#google-oauth) | ||
- [Configuration and usage](#configuration-and-usage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we keep the "library usage" v "command features" sections? Users have been confused by the dual nature of roo_on_rails
(it's both a library/framework complement and a CLI, usable separately).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely! I was a bit confused by this table of content myself, partly because it changed while I was working on this PR. I'll rename "Configuration and usage" to "Library usage" 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
private | ||
|
||
def bus_credentials_blank? | ||
routemaster_url.blank? && routemaster_uuid.blank? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be routemaster_url.blank? || routemaster_uuid.blank?
? (Assuming both are mandatory)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes indeed, good spot, thank you.
Here's a proposal for how publishing events could look from model classes. It's based on the code in
orderweb
but I've cleaned up the naming/implementation and made it more amenable to publishing multiple events from a single model by making multiple publishers the default.