eventbus

package module
v0.0.0-...-03782d0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 5, 2015 License: MIT Imports: 10 Imported by: 0

README

Overview

The purpose of this project is to provide a unified event bus that can be used to trigger actions in browser-based JavaScript applications as well as from applications in other languages that are running on remote servers. Events are added to the bus using an HTTP end point and then are distributed to attached listeners via WebSockets.

Communications Flow

This project is largely about the design of applications using this architecture, not just this implementation. Alternative implementations could be created with other components, such as existing open source or commercial message queues and web servers.

Thus, some of the key considerations are:

  • What does an end-to-end event-driven web application look like?
  • Is it a good way to develop web applications?
  • What are the benefits and drawbacks when compared to existing synchronous and synchronous/asynchronous solutions?

This system's design borrows heavily from:

  • The event-driven design of JavaScript.
  • Concepts for micro-services.
  • Existing queue systems such as ZeroMQ and Kafka.

Status

This project is brand new. It is NOT production-ready.

Design

Definitions

Client

A client is a web browser, native client or application. Clients must always identify themselves after connecting via their WebSocket. Clients must also always include their identity in their event context when creating new events using the identifier key.

Services

A service is application code that processes events and executes business logic. Services must always authenticate themselves after connecting via their WebSocket. Services must also always pass their authorization token whenever they create new events.

Frontend

The sample front end is HTML and JavaScript, however native clients could also be used.

The system relies solely on events as the mechanism for dealing with input and output. For example, a form is filled in an the submit button is pressed. This results in an event. Events are sent to local listeners to update the UI as well as to a remote event bus for any additional processing. When a listener on the remote event bus handles the event it will fire a new event, directed towards the client's event bus (via WebSockets) where a listener handles the event and updates the UI. Browser UI events are translated from the UI event (i.e. button clicked) to an event that is domain-specific (for example "check-domain-availability").

Backend

The backend is purely functional event handlers. A listener handles the event, perhaps firing off events to the bus, potentially handled by other listeners or the client for UI updates. A backend listener could be implemented in any language as long as it can make HTTP calls and has a WebSocket library.

The backend consists of the following:

  • A static file server for serving up the JS/HTML/CSS files
  • An HTTP endpoint for pushing events into the event bus
  • A WebSocket endpoint for establishing WebSocket connections
  • Event routing logic for determining who can receive an event
  • A stateful identity store for tracking client message source
  • An authentication layer for services

The EventBus Queue

The event bus is a publish/subscribe queue. Events are published to the bus using a synchronous HTTP call. A successfully added event returns a 200. Any other response code indicates that the event add failed and should be retried.

A successfully added event is persisted in an event store. The current implementation is in-memory and disappears when the application terminates.

Subscribers always receive events via WebSockets. Clients only receive events that are addressed to them. Services receive all events.

There is currently no guarantee that an event will be delivered.

Running

Install Foreman.

Set up a .env file as follows:

HTTP_FILE_SERVER_HOST=locahost
HTTP_FILE_SERVER_PORT=3000
HTTP_EVENTBUS_SERVER_HOST=localhost
HTTP_EVENTBUS_SERVER_PORT=3001

Then run foreman start.

CORS

If you are running the service under a different server (such as Apache or nginx) then you will need to make sure that the correct CORS headers are present when HTML files are requested.

The static HTML server response headers must include the following CORS headers:

Access-Control-Allow-Origin: eventbus-url
Access-Control-Allow-Headers: Content-Type

Where eventbus-url is replaced with the URL for the EventBus server.

Docs

API documentation is at https://godoc.org/github.com/aeden/eventbus.

Demo

There is an demo JavaScript web application in the static directory. To see it in action, do the following:

Your web browser must support WebSockets.

FAQ

In which I explain certain design decisions.

Why not use WebSockets for both publishing events in and distributing events out?

The HTTP protocol is ideally suited for the synchronous nature of publishing an event to the queue. The system can take advantage of the protocol's built-in mechanisms for authorization, errors, etc. On the other hand, WebSockets are great for streaming data once a connection is established. Server-sent events (SSE) are another option: http://www.html5rocks.com/en/tutorials/eventsource/basics/ - right now IE has no support for SSE but does have support for WebSockets.

Issues

  • Currently the EventBus WebSocket service handles only unecrypted calls.
  • The event system does not guarantee at-least-once delivery to connected services.
  • Events are persistent but subscribers have no way of getting at old events.

Documentation

Overview

Package eventbus provides a remote event bus that accepts new events via HTTP POSTs and broadcasts events via WebSockets.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CorsHostAndPort

func CorsHostAndPort(v string) option

Configure the CORS host and port for the EventBus server. This is the host and port where JavaScript client calls are coming from.

func HostAndPort

func HostAndPort(v string) option

Configure the host and port of the EventBus server.

func Services

func Services(in io.Reader) option

Configure the services that will attach to the EventBus server.

Types

type Event

type Event struct {
	Name    string            `json:"name"`
	Data    interface{}       `json:"data"`
	Context map[string]string `json:"context"`
}

Represents a single event fired by either a client or a service.

func NewEvent

func NewEvent() *Event

Construct a new event and return a pointer to it.

type EventStore

type EventStore interface {
	// Write the event to the event store. Returns an error
	// if the event fails to write.
	WriteEvent(*Event) error
}

Event stores are used to persist events when they are created.

type InMemoryEventStore

type InMemoryEventStore struct {
	Events []*Event
}

A simple in-memory event store that puts all events in an Array.

func NewInMemoryEventStore

func NewInMemoryEventStore() *InMemoryEventStore

Construct a new in-memory event store. Returns a pointer to the event store.

func (*InMemoryEventStore) WriteEvent

func (store *InMemoryEventStore) WriteEvent(event *Event) (err error)

Save the event in an in-memory array.

type NullEventStore

type NullEventStore struct {
}

Event store that simply discards events.

func NewNullEventStore

func NewNullEventStore() *NullEventStore

Construct a new NullEventStore and return a pointer to it.

func (*NullEventStore) WriteEvent

func (store *NullEventStore) WriteEvent(event *Event) (err error)

Silently discard the event.

type Server

type Server struct {
	// contains filtered or unexported fields
}

The EventBus server.

func NewServer

func NewServer(opts ...option) *Server

Configure a new server that is ready to be started.

func (*Server) Start

func (server *Server) Start()

Start the event bus server for handling JSON events over HTTP.

This function starts a handler on the root that is used for POST requests to construct new events. It also starts a WebSocket handler on /ws that is used for broadcasting events to the client or service.

type ServiceConfig

type ServiceConfig struct {
	Name  string `json:"name"`
	Token string `json:"token"`
}

Configuration for a service that may attach.

Directories

Path Synopsis
Package fileserver is a simple file server for serving up static files for the JavaScript demo.
Package fileserver is a simple file server for serving up static files for the JavaScript demo.
Package middleware provides shared middleware that is used in HTTP services.
Package middleware provides shared middleware that is used in HTTP services.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL