Skip to content
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

Add queue-based event pub to make sure events are published in order #97

Merged
merged 10 commits into from
Nov 2, 2017

Conversation

derekkraan
Copy link
Contributor

@derekkraan derekkraan commented Oct 30, 2017

Run the included spec on master to see what happens without the new EventPublisher

configuration.event_handlers.each do |handler|
begin
handler.handle_message event
rescue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rescue can be moved down, this makes the code a bit more readable

def process_events
rescue
end

Copy link
Contributor Author

@derekkraan derekkraan Oct 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't do that since we don't have a reference to the event at the method body level.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh, you are right

Thread.current[:events_queue] ||= Queue.new
end

def skip_if_locked(&block)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a better name is skip_if_publishing or skip_if_not_main_thread

Copy link
Member

@lvonk lvonk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this a lot 👍 . Makes the intended way of publishing much more clear and explicit.

module Sequent
module Core
#
# EventPublisher ensures that, for every thread, events will be published in the order in which they are meant to be published.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "... will be published breadth (or width) first" is better.

To clarify, with breadth first I mean: first all first level events than the consequences of those events.

#
# If you do not want this, you are free to implement your own version of EventPublisher and configure sequent to use it.
#
class EventPublisher
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am thinking to split this in 2 concerns. This might help in understanding the concepts better and might be easier to extend with other strategies. This also allows us to support the current behavior and be backward compatible.

  1. The Events queue with is basically process_events
  2. The FIFO strategy" which is basically events.each { |event| events_queue.push(event) }.

When someone want LIFO (or depth first) the event should be prepended to the Queue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should hold off on implementing something like this until someone asks for it / needs it.

private

def events_queue
Thread.current[:events_queue] ||= Queue.new
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Queue only supports FIFO I think. We can safely use Array here to support both FIFO and LIFO.

Copy link
Contributor Author

@derekkraan derekkraan Nov 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should hold off on implementing something like this until someone asks for it / needs it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are changing the current behavior so I think it is good to support both cases and the current one as default, with maybe a warning message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither of those scenarios is the current one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right... Okay, let's communicate this in the changelog when we release.

end
ensure
repository.clear
commands.each do |command|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a one-liner: each. {}

@@ -57,6 +46,31 @@ def remove_event_handler(clazz)

private

def process_commands
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract this to a separate class like the EventPublisher. Both are quite similar in intent and behavior. Same suggestion made for the EventPublisher also apply here then :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CommandService is a separate class like EventPublisher already.

@derekkraan
Copy link
Contributor Author

@erikrozendaal @s0meone @bjpbakker feedback? We will be merging this shortly.

@bjpbakker
Copy link
Contributor

I do like this change, it solves a bunch of problems with published event ordering.

That said, current behavior is changed quite a lot, and may actually break current implementations. Most likely the tests won't cover this (because often they simply assert published events). That makes it tough to keep production code bases that are not in active development up to date with sequent.

Can we provide the current behavior via a configuration option?

@derekkraan
Copy link
Contributor Author

This behaviour is configurable to a certain degree: One is free to simply implement her own version of EventPublisher and configure Sequent to use that with Sequent.configuration.event_publisher = YourEventPublisher. This is a couple of steps beyond trivial, but I feel that it's not an inordinate amount of work.

I'd rather we not officially support the legacy behaviour and the code that goes along with it.

If we get questions about this I'd be more than happy to help people gut EventPublisher and CommandService to suit their needs.

@derekkraan
Copy link
Contributor Author

I think also that we should release this with a minor level version number increase to indicate that there is new functionality being introduces. This would be version 1.1.0.

@bjpbakker
Copy link
Contributor

If we choose to no longer support the current order of event publishing (and stick with semantic versioning) we should bump to 2.0. This change currently is not backwards compatible.

@derekkraan
Copy link
Contributor Author

That depends on your definition of "backwards compatible". Every change is potentially backwards incompatible, yet we don't increment major version number for every single bugfix.

The question is whether the new ordering is compatible with the old ordering. The answer is: that depends on how our users have implemented their systems and to what degree they are dependent on the old ordering. I suspect that most of them are not, making it for most (or all) users a backwards compatible change.

Or do you suspect that this will break functionality for a non-trivial percentage of Sequent users?

@derekkraan derekkraan removed the request for review from s0meone November 1, 2017 12:02
@erikrozendaal
Copy link
Member

Running additional (event handler) generated commands in the same transaction may lead to huge, complicated transactions. This may not be what we want. But I guess handling new commands in separate transactions requires a lot of additional infrastructure (persistent queues, background jobs, etc).

So I guess this is fine, but I think we should discourage people from generating new commands in event handlers for immediate execution.

@derekkraan
Copy link
Contributor Author

@bjpbakker let's talk about version numbers on Friday. Merging this since that isn't a blocking issue.

@derekkraan derekkraan merged commit 29078cb into master Nov 2, 2017
@stephanvd stephanvd deleted the event_handler_queue branch June 8, 2018 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants