A lightweight event dispatcher for go project to implement event driven programming
go get -u github.com/go-study-lab/event
Jump to Usage Example
event.Dispacthcer()
It will return a singleton of *event.eventDispatcher
, which is a core component and all functionality would supply through it by.
func (dispatcher *eventDispatcher) Subscribe(e *Event, l IListener)
Subscribe
method can specify an event listener for a specific event.
An event listener must implement IListener
interface, we will explain this interface in next section.
func (dispatcher *eventDispatcher) Dispatch(e *Event)
Dispatcher's Dispatch
method would let us push an event, then the dispatcher would execute event's bound listeners.
func (dispatcher *eventDispatcher) HasEventListener(e *Event) bool
func (dispatcher *eventDispatcher) RemoveEventListener(e *Event, l IListener)
Type Event
is an event wrapper for concrete event data
type Event struct {
eventName string
eventTime time.Time
concreteEvent IEvent
eventType string
}
A concrete event must implements interface IEvent
type IEvent interface {
EventName() string
}
func NewEvent(concreteEvent IEvent) *Event
This is a factory method of Event instance.
func (e *Event) OccurredOn() time.Time
Return event occurred time.
func (e *Event) EventData() IEvent
Return concrete event data.
func (e *Event) EventName() string
Return name of event.
IListener
defines behaviors an event listener must implements.
type IListener interface {
EventHandler() Handler
AsyncProcess() bool
}
type Handler func(e *Event)
EventHandler
returns a handler func for event bound to listener.
Given a listener instance *listener
, it should provide EventHandler
like below:
func (*listener) EventHandler() event.Handler {
return func(e *event.Event) {
fmt.Println("Event received")
}
}
func (*listener) AsyncProcess() bool {
return false
}
If AsyncProcess
returned false, event.Handler
func provided by EventHandler
would be executed in same goroutine with the event trigger func,
this means event trigger would be blocked until all his synchronized listener's handler were finished.
In the contrast event.Handler
would be executed in other goroutine and event trigger would not
be blocked to wait listener's completion.
All dispatcher functions' demo can be found in Example Code.
This section will showcase how to define event and listener, then dispatch/publish an event.
- Define an
UserCreated
event.
type UserCreated struct {
UserId int
UserName string
Tx *Tx
}
type Tx struct {
// Mock as a DB transaction
DSN string
Tid int64
}
func (*UserCreated) EventName() string {
return "UserCreated"
}
func UserCreatedEvent(e *UserCreated) *event.Event {
return event.NewEvent(e)
}
- Define corresponding listener for
UserCreated
event.
type UserCreatedListener struct {
}
func (*UserCreatedListener) EventHandler() event.Handler {
return func(e *event.Event) {
var eData *UserCreated
var ok bool
if eData, ok = e.EventData().(*UserCreated); !ok {
fmt.Println("can not convert event data to type *UserCreated")
return
}
fmt.Printf("event data, userId:%d, userName:%s, Tx:%p \n", eData.UserId, eData.UserName, eData.Tx)
}
}
// When we want to use a same
// DB transaction in event trigger and listener to get ACID assurance, then
// AsyncProcess must return false.
func (*UserCreatedListener) AsyncProcess() bool {
return false
}
- Bind event and listener in init func.
func init() {
eventDispatcher := event.Dispatcher()
eventDispatcher.Subscribe(UserCreatedEvent(new(UserCreated)), new(UserCreatedListener))
}
- Publish/Dispatch event
func PublishCreateUserEvent() {
user := &User{
UserId: 1,
UserName: "KK",
}
tx := &domainevent.Tx{DSN: "localhost:3306/test_db", Tid: 1}
fmt.Printf("Tx in envet trigger: %p \n", tx)
// assume use tx to create user, then publish a userCreated event
event.Dispatcher().Dispatch(event.NewEvent(&domainevent.UserCreated{
UserId: user.UserId,
UserName: user.UserName,
Tx: tx, // in event handler, we can use this tx to execute other db operation
// in the same transaction , this method will ensure event trigger and listener as
// an atomically processed unit in system.
}))
}
func main() {
PublishCreateUserEvent()
}
You can find this example's code in Example Code.