Skip to content

A lightweight event dispatcher for go project to implement event driven programming

License

Notifications You must be signed in to change notification settings

go-study-lab/event

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

event

A lightweight event dispatcher for go project to implement event driven programming

installation

go get -u github.com/go-study-lab/event

Jump to Usage Example

Dispatcher Methods

Load event dispatcher singleton

event.Dispacthcer()

It will return a singleton of *event.eventDispatcher, which is a core component and all functionality would supply through it by.

Bind event listener

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.

Publish event

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.

Verify event has listeners

func (dispatcher *eventDispatcher) HasEventListener(e *Event) bool

Remove event listener

func (dispatcher *eventDispatcher) RemoveEventListener(e *Event, l IListener)

Event

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
}

Event Methods

NewEvent

func NewEvent(concreteEvent IEvent) *Event

This is a factory method of Event instance.

OccurredOn

func (e *Event) OccurredOn() time.Time

Return event occurred time.

EventData

func (e *Event) EventData() IEvent

Return concrete event data.

EventName

func (e *Event) EventName() string

Return name of event.

IListener

IListener defines behaviors an event listener must implements.

type IListener interface {
    EventHandler() Handler
    AsyncProcess() bool
}

type Handler func(e *Event)

EventHandler Method

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")
    }
}

AsyncProcess

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.

Usage Examples

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.

  1. 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)
}
  1. 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
}
  1. Bind event and listener in init func.
func init() {
    eventDispatcher := event.Dispatcher()
    eventDispatcher.Subscribe(UserCreatedEvent(new(UserCreated)), new(UserCreatedListener))
}
  1. 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.

About

A lightweight event dispatcher for go project to implement event driven programming

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages