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

Feature: central event backbone in the server for analytics #390

Closed
jniles opened this issue May 11, 2016 · 1 comment
Closed

Feature: central event backbone in the server for analytics #390

jniles opened this issue May 11, 2016 · 1 comment

Comments

@jniles
Copy link
Contributor

jniles commented May 11, 2016

One of bhima's central focuses is transparency. This should not be limited to any particular portion of the application, but should run throughout the design of the entire system.

We have the facility to implement real-time analytics on our server/database infrastructure easily via event emitters. Since we have a transitioned into APIs for all data CREATES, UPDATES, and DELETEs, we can capture each of these individual actions initiated by any user and display them to all users that wish to see it.

Design

I propose we implement a new library, eventd, that every controller can import and use to broadcast actions that can be captured to write to logs or send to a client via server-sent events. The API will be something like:

const eventd = require('lib/eventd');

// emit a "CREATE" event to show that something was created in the database
eventd.emit(eventd.constants.CREATE, { uuid : '...', user : req.session.user });

// emit a "LOGIN" event to show that someone logged in.
eventd.emit(eventd.constants.LOGIN, { uuid : '...', user: req.session.user });

// create a listener on /events that will send all events to the client
const app = require('express')();
app.get('/events', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');

  // emit every event to the client
  const events = eventd.subscribe(event => {
    res.write('data: ' + JSON.stringify(event));
    res.flush();
  });

  // remove the listener when the client kills the connection
  res.on('close', () => eventd.unsubscribe(events)); 
});

If we had this infrastructure, you can imagine the ability to quickly add event streams for user login/logout events, database operations, reporting, etc. All of these could be available to power feeds on the client to give real time information about the system.

@jniles jniles added this to the 2.x Presentation - Hospital/ Application Core milestone May 11, 2016
@jniles
Copy link
Contributor Author

jniles commented May 12, 2016

After some discussion with @sfount, this proposed feature accounts for real-time analytics, but does not have a storage mechanism to see "events from today" or "events this week".

To account for this, I propose storing events in a database table event that looks like this:

timestamp user_id type data
2016-05-12 12:19:40 2 CREATE { table : "patient"}
2016-05-12 12:23:21 7 UPDATE { table : "user", id : 2 }

... where data is a JSON column that could store variable information.

With this new proposal, the client would connect to two server routes:

  1. /events will simply return a list of events to the client, limited to the last day by default. It will be downloaded once.
  2. /stream will be a real-time stream of events, published via server-sent events.

An additional limitation of this model is that events cannot be shared across cores (since the event emitter will only exist in a single process. Eventually, we could move this event emitter architecture to a shared database like redis. See this example for more information.

jniles referenced this issue in jniles/bhima May 13, 2016
This commit creates an event emitter that will serve events in real-time
to any client listeners from throughout the application.  The current
infrastructure uses the native `events` module in NodeJS, but future
implementation might take advantage of redis for publish/subscribe.

Closes #390.
jniles referenced this issue in jniles/bhima May 16, 2016
This commit adds the class `Topic`, a redis-based event emitter
permitting controllers to subscribe/unsubscribe from channels and react
to events on those channels.  Redis is already an installation
requirement for the application, so this adds minimal dependency
overhead.

The basic usage looks like this:
```js
// import Topic
const Topic = require('topic');

Topic.subscribe('channelName', (data) => console.log(data));
Topic.publish('channelName, { key : 'value' });
Topic.unsubscribe('channelName');
```

Closes #390.
jniles referenced this issue in jniles/bhima May 19, 2016
This commit adds the class `Topic`, a redis-based event emitter
permitting controllers to subscribe/unsubscribe from channels and react
to events on those channels.  Redis is already an installation
requirement for the application, so this adds minimal dependency
overhead.

The basic usage looks like this:
```js
// import Topic
const Topic = require('topic');

Topic.subscribe('channelName', (data) => console.log(data));
Topic.publish('channelName, { key : 'value' });
Topic.unsubscribe('channelName');
```

Closes #390.
jniles referenced this issue in jniles/bhima May 19, 2016
This commit adds the class `Topic`, a redis-based event emitter
permitting controllers to subscribe/unsubscribe from channels and react
to events on those channels.  Redis is already an installation
requirement for the application, so this adds minimal dependency
overhead.

The basic usage looks like this:
```js
// import Topic
const Topic = require('topic');

Topic.subscribe('channelName', (data) => console.log(data));
Topic.publish('channelName, { key : 'value' });
Topic.unsubscribe('channelName');
```

Closes #390.
jniles referenced this issue in jniles/bhima May 23, 2016
This commit adds the class `Topic`, a redis-based event emitter
permitting controllers to subscribe/unsubscribe from channels and react
to events on those channels.  Redis is already an installation
requirement for the application, so this adds minimal dependency
overhead.

The basic usage looks like this:
```js
// import Topic
const Topic = require('topic');

Topic.subscribe('channelName', (data) => console.log(data));
Topic.publish('channelName, { key : 'value' });
Topic.unsubscribe('channelName');
```

Closes #390.
jniles referenced this issue in jniles/bhima May 23, 2016
This commit adds the class `Topic`, a redis-based event emitter
permitting controllers to subscribe/unsubscribe from channels and react
to events on those channels.  Redis is already an installation
requirement for the application, so this adds minimal dependency
overhead.

The basic usage looks like this:
```js
// import Topic
const Topic = require('topic');

Topic.subscribe('channelName', (data) => console.log(data));
Topic.publish('channelName, { key : 'value' });
Topic.unsubscribe('channelName');
```

Closes #390.
@sfount sfount closed this as completed in c81fa4e May 23, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant