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

Use EventMatcher when registering event handlers #84

Closed
maxekman opened this issue Feb 13, 2017 · 3 comments
Closed

Use EventMatcher when registering event handlers #84

maxekman opened this issue Feb 13, 2017 · 3 comments

Comments

@maxekman
Copy link
Member

maxekman commented Feb 13, 2017

An example:

// EventBus is an interface defining an event bus for distributing events.
type EventBus interface {
	...

	// AddHandler adds a handler for an event.
	AddHandler(EventHandler, EventMatcher)

	...
}
// EventMatcher is used to match events, used when adding event handlers.
type EventMatcher interface {
	MatchesEvent(EventType) bool
}

// AnyEvent is an EventMatcher that matches any event.
type AnyEvent struct{}

// MatchesEvent imlpements the MatchesEvent method of the EventMatcher interface.
func (m AnyEvent) MatchesEvent(e EventType) bool {
	return true
}

// OneEvent is an EventMatcher that matches a single event.
type OneEvent struct {
	Event EventType
}

// MatchesEvent imlpements the MatchesEvent method of the EventMatcher interface.
func (m OneEvent) MatchesEvent(e EventType) bool {
	return m.Event == e
}

// ManyEvents is an EventMatcher that matches if the event is in the slice.
type ManyEvents []EventType

// MatchesEvent imlpements the MatchesEvent method of the EventMatcher interface.
func (m OneEvent) MatchesEvent(e EventType) bool {
	// return true if e is in the slice.
}
@grrtrr
Copy link
Contributor

grrtrr commented Dec 2, 2017

Thank you for sharing this. This idea seemed neat to me and so I had it copied in one of my projects.

After using it for a while, I ended up merging both handlers,

  • it was more straightforward to do the event-filtering (EventMatcher) at the top of the EventHandler,
  • it would return before any shared resources (locks) needed to be taken,
  • having to maintain 2 functions per event greatly increased the amount of duplicate code.

Unless there are huge performance considerations (which I doubt, since go makes running many thousands of goroutines at the same time possible), I found it led to a simpler overall design.

@maxekman
Copy link
Member Author

maxekman commented Dec 3, 2017

Glad it could help! I would love to hear more about your implementation, maybe you can show an example in a gist?

@grrtrr
Copy link
Contributor

grrtrr commented Dec 3, 2017

This is in magicbus,

  • an event is a directed message (Source() -> Dest(), it is possible to make Source() optional);
  • the EventHandler both
    • filters events by relevance and
    • processes them, as per above comment.

There are 2 ways to process events:

  • for Aggregates, these are multiplexed with Commands (i.e. at most 1 Command or Event is being processed at any time), as per Actor "serialized code" principle;
  • everything else (e.g. loggers, writers) can subscribe as Observer, which means immediate notification.

(Aggregates only get the events whose Dest() matches the AggregateID, and only if they implement the optional EventHandler interface).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants