logo Buffalo slack logo
Events
Guides

Events#

Desde 0.13.0-beta.2

The events package allows for Go applications, including Buffalo applications, to listen, and emit, global event messages.

Listening for Events#

To start listening for events a events#Listener must first be registered with the events package.

func init() {
  _, err := events.Listen(func(e events.Event) {
    // do work
  })
}

Once registered this new listener function will be sent all events emitted through the events package.

Emitting Events#

When emitting events the Kind attribute should be a unique, but constant, string. It is this attribute that users will use to determine how to respond to events they receive.

It is recommended to namespace this attribute like such, with error events being suffixed with :err.

"<package-name>:<additional-names>:<optional-error>"
"myapp:foo:start"
"myapp:foo:stop"
"mypkg:workers:bar:err"

This naming pattern makes it easier for users to filter events to only those that they care about. See Filtering Events for more details.


There are multiple ways to emit an events#Event in your Go code. The events#EmitError and events#EmitPayload functions both accept a payload interface{} argument. It is recommended to use events#Payload for payloads; any other type passed in will get converted into a events#Payload with the argument set in the payload with the key, data.

func MyHandler(c buffalo.Context) error {
  e := events.Event{
    Kind:    "coke:myhandler:hello",
    Message: "hi!",
    Payload: events.Payload{"context": c},
  }
  if err := events.Emit(e); err != nil {
    return err
  }
  return c.Render(200, r.HTML("index.html"))
}
func MyHandler(c buffalo.Context) error {
  if err := events.EmitError("coke:myhandler:hello:err", errors.New("boom"), c); err != nil {
    return err
  }
  return c.Render(200, r.HTML("index.html"))
}
func MyHandler(c buffalo.Context) error {
  p := events.Payload{
    "message": "hi!",
  }
  if err := events.EmitPayload("coke:myhandler:hello", p); err != nil {
    return err
  }
  return c.Render(200, r.HTML("index.html"))
}

Filtering Events#

In the Emitting Events section the naming convention for events#Event.Kind is described. By the checking the value of events#Event.Kind.

direct match
matching with a switch statement
matching error events
matching on prefix
// direct match
events.Listen(func(e events.Event) {
  if e.Kind != buffalo.EvtRouteStarted {
    // do nothing
    return
  }
  // do work on the route event
})

Stop Listening for Events#

When registering a new events#Listener a events#DeleteFn is returned. This function should be held on to and used when you want to remove the added listener.

deleteFn, err := events.Listen(func(e events.Event) {
  // do work
})
if err != nil {
  return err
}
defer deleteFn()

Listening with Plugins#

To enable a plugin to a receive a JSON version of emitted events, the plugin can set the events#Command.BuffaloCommand value to events when listing the available commands for the plugin.

availableCmd
listenCmd
// availableCmd
var availableCmd = &cobra.Command{
  Use:   "available",
  Short: "a list of available buffalo plugins",
  RunE: func(cmd *cobra.Command, args []string) error {
    plugs := plugins.Commands{
      {Name: "listen", UseCommand: "listen", BuffaloCommand: "events", Description: listenCmd.Short, Aliases: listenCmd.Aliases},
    }
    return json.NewEncoder(os.Stdout).Encode(plugs)
  },
}

Integrating a Messaging Queue#

It is often desirable to take events emitted and send them to a message queue, such as Kafka or Redis, to be processed externally. The events package does not have a directhook for this sort of functionality, the most direct way of enabling this behavior is to register a events#Listener that can then hand the event over to the appropriate message queue.

events.Listen(func(e events.Event) {
  myMessageQ.DoWork(e)
})

Known Events#

Application Events#

The following events are known to be emitted by Buffalo during the application lifecyle.

Constant String Emitted When Payload
buffalo.EvtAppStart "buffalo:app:start" buffalo#App.Serve is called app: buffalo#App
buffalo.EvtAppStartErr "buffalo:app:start:err" an error occurs calling buffalo#App.Serve app: buffalo#App
buffalo.EvtAppStop "buffalo:app:stop" buffalo#App.Stop is called app: buffalo#App
buffalo.EvtAppStopErr "buffalo:app:stop:err" an error occurs calling buffalo#App.Stop app: buffalo#App
buffalo.EvtRouteStarted "buffalo:route:started" a requested route is being processed route: buffalo#RouteInfo app: buffalo#App context: buffalo#Context
buffalo.EvtRouteFinished "buffalo:route:finished" a requested route is completed route: buffalo#RouteInfo app: buffalo#App context: buffalo#Context
buffalo.EvtRouteErr "buffalo:route:err" there is a problem handling processing a route route: buffalo#RouteInfo app: buffalo#App context: buffalo#Context
buffalo.EvtWorkerStart "buffalo:worker:start" buffalo#App.Serve is called and workers are started app: buffalo#App
buffalo.EvtWorkerStartErr "buffalo:worker:start:err" an error occurs when starting workers app: buffalo#App
buffalo.EvtWorkerStop "buffalo:worker:stop" buffalo#App.Stop is called and workers are stopped app: buffalo#App
buffalo.EvtWorkerStopErr "buffalo:worker:stop:err" an error occurs when stopping workers app: buffalo#App
buffalo.EvtFailureErr "buffalo:failure:err" something can’t be processed at all. it is a bad thing app: buffalo#App context: buffalo#Context

Buffalo Dev Events#

The following events are known to be emitted by the buffalo dev during the development lifecyle.

String Emitted When Payload
"buffalo:dev:raw" an applicable file is modified event: fsnotify#Event
"buffalo:dev:build:started" a build has started event: fsnotify#Event cmd: string of the go build command (example: "go build foo")
"buffalo:dev:build:finished" a build has completed event: fsnotify#Event pid: PID of the newly running binary build_time: the duration of the build
"buffalo:dev:build:err" a build error has occurred event: fsnotify#Event cmd: string of the go build command (example: "go build foo")