diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..b6924c5a97 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.dockerignore +Dockerfile +docker-compose.yml +.git diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..c26913aa7c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM node:6.10.3 + +RUN useradd -U -d /opt/refocus refocus +ENV HOME=/opt/refocus +COPY . $HOME +RUN chown -R refocus:refocus $HOME + +USER refocus +WORKDIR $HOME +RUN npm install + +# sleep is to support pause during startup for deploys in kubernetes - delays start of refocus container to let pg and redis containers to start within the same pod. +ENV SLEEP=0 +ENV PGHOST=pg +ENV REDIS_URL=//redis:6379 + +EXPOSE 3000 + +CMD [ "/bin/sh", "-c", "sleep $SLEEP; npm start" ] diff --git a/config/toggles.js b/config/toggles.js index 0f6ee5ff30..f5334ee162 100644 --- a/config/toggles.js +++ b/config/toggles.js @@ -89,6 +89,10 @@ const longTermToggles = { enforceWritePermission: environmentVariableTrue(pe, 'ENFORCE_WRITE_PERMISSION'), + // Add some instrumentation for real time events + instrumentRealtimeEvents: + environmentVariableTrue(pe, 'INSTRUMENT_REALTIME_EVENTS'), + // Enforce that all API requests have valid API token requireAccessToken: environmentVariableTrue(pe, 'REQUIRE_ACCESS_TOKEN'), diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..dd82646385 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: '2' +services: + refocus-app: + build: . + ports: + - "3000:3000" + depends_on: + - "redis" + - "pg" + redis: + image: "redis:3.2.8" + expose: + - 6379 + pg: + image: "postgres:9.6.2" + expose: + - 5432 + diff --git a/docs/docs/01-quickstart.md b/docs/docs/01-quickstart.md index 2ef2cb1b52..dfbadd6d77 100644 --- a/docs/docs/01-quickstart.md +++ b/docs/docs/01-quickstart.md @@ -83,6 +83,7 @@ You have two ways to deploy Refocus. Select the one that best meets your needs. - I want [one-click Heroku deployment](./03-quickstartheroku.html) - I want to [download and build and deploy locally](./04-quickstartlocal.html) +- I want to [run Refocus locally as docker container](./05-quickstartlocaldocker.html) Refocus requires that both Redis and PostgreSQL are running. After Refocus is deployed, create an account and sign in. diff --git a/docs/docs/05-quickstartlocaldocker.md b/docs/docs/05-quickstartlocaldocker.md new file mode 100644 index 0000000000..fcb0321828 --- /dev/null +++ b/docs/docs/05-quickstartlocaldocker.md @@ -0,0 +1,12 @@ +--- +layout: docs +title: Quick Start with Local Docker +--- + +# QuickStart with Local Docker +# Prerequisites +1. Install docker [docker-for-mac](https://docs.docker.com/docker-for-mac/install/). +# Start refocus with dependencies +1. Clone this git repository. +2. Run `cd refocus`. +3. Run `docker-compose up` diff --git a/realtime/redisPublisher.js b/realtime/redisPublisher.js index bb6277870b..5ba7fb95d7 100644 --- a/realtime/redisPublisher.js +++ b/realtime/redisPublisher.js @@ -14,6 +14,7 @@ const pub = require('../cache/redisCache').client.pub; const channelName = require('../config').redis.channelName; const sampleEvent = require('./constants').events.sample; +const featureToggles = require('feature-toggles'); /** * When passed an sample object, either a sequelize sample object or @@ -81,7 +82,13 @@ function publishObject(inst, event, changedKeys, ignoreAttributes) { } if (obj[event]) { - return pub.publish(channelName.toString(), JSON.stringify(obj)); + const objectAsString = JSON.stringify(obj); + if (featureToggles.isFeatureEnabled('instrumentRealtimeEvents')) { + console.log(`[RT] publishTimestamp=${(new Date()).toISOString()} ` + + `size=${objectAsString.length}`); + } + + return pub.publish(channelName, objectAsString); } return obj; diff --git a/realtime/redisSubscriber.js b/realtime/redisSubscriber.js index b430a67f80..f40f3c6c49 100644 --- a/realtime/redisSubscriber.js +++ b/realtime/redisSubscriber.js @@ -12,6 +12,7 @@ 'use strict'; // eslint-disable-line strict const emitter = require('./socketIOEmitter'); const sub = require('../cache/redisCache').client.sub; +const featureToggles = require('feature-toggles'); /** * Redis subscriber uses socket.io to broadcast. @@ -21,6 +22,11 @@ const sub = require('../cache/redisCache').client.sub; */ module.exports = (io) => { sub.on('message', (channel, mssgStr) => { + if (featureToggles.isFeatureEnabled('instrumentRealtimeEvents')) { + console.log(`[RT] subscribeTimestamp=${(new Date()).toISOString()} ` + + `size=${mssgStr.length}`); + } + // message object to be sent to the clients const mssgObj = JSON.parse(mssgStr); const key = Object.keys(mssgObj)[0]; diff --git a/realtime/socketIOEmitter.js b/realtime/socketIOEmitter.js index 8be1b96ecd..55f8e1ec88 100644 --- a/realtime/socketIOEmitter.js +++ b/realtime/socketIOEmitter.js @@ -14,6 +14,7 @@ const rtUtils = require('./utils'); const initEvent = 'refocus.internal.realtime.perspective.namespace.initialize'; +const featureToggles = require('feature-toggles'); module.exports = (io, key, mssgObj) => { const obj = rtUtils.parseObject(mssgObj[key], key); @@ -28,6 +29,10 @@ module.exports = (io, key, mssgObj) => { if (nsp && rtUtils.shouldIEmitThisObj(nsp, obj)) { // newObjectAsString contains { key: {new: obj }} io.of(nsp).emit(key, newObjectAsString); + + if (featureToggles.isFeatureEnabled('instrumentRealtimeEvents')) { + console.log(`[RT] namespace=${nsp} bytes=${newObjectAsString.length}`); + } } } };