From 06ea13225735a5fadbf9a017c8074e7f71007ac7 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Tue, 5 Apr 2016 14:45:09 -0700 Subject: [PATCH] Add timed cache to user count queries --- server/boot/about.js | 33 +++++++++++++++++-------------- server/utils/rx.js | 22 ++++++++++++++++++++- server/views/resources/about.jade | 8 -------- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/server/boot/about.js b/server/boot/about.js index 04199db81d..455f39fc0d 100644 --- a/server/boot/about.js +++ b/server/boot/about.js @@ -2,40 +2,43 @@ import { Observable } from 'rx'; import dedent from 'dedent'; import moment from 'moment'; -import { observeMethod } from '../utils/rx'; +import { timeCache, observeMethod } from '../utils/rx'; function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } +// userCount(where: Object) => Observable[Number] +// getCertCount(userCount: userCount, cert: String) => Observable[Number] +function getCertCount(userCount, cert) { + return userCount({ [cert]: true }) + // using This-Bind operator + ::timeCache(2, 'hours'); +} + export default function about(app) { const router = app.loopback.Router(); const User = app.models.User; - const userCount$ = observeMethod(User, 'count'); + const userCount = observeMethod(User, 'count'); + const frontEndCount$ = getCertCount(userCount, 'isFrontEndCert'); + const dataVisCount$ = getCertCount(userCount, 'isDataVisCert'); + const backEndCount$ = getCertCount(userCount, 'isBackEndCert'); function showAbout(req, res, next) { const daysRunning = moment().diff(new Date('10/15/2014'), 'days'); Observable.combineLatest( - userCount$(), - userCount$({ isFrontEndCert: true }), - userCount$({ isDataVisCert: true }), - userCount$({ isBackEndCert: true }), - ( - userCount, - frontEndCount = 0, - dataVisCount = 0, - backEndCount = 0 - ) => ({ - userCount: numberWithCommas(userCount), + frontEndCount$, + dataVisCount$, + backEndCount$, + (frontEndCount = 0, dataVisCount = 0, backEndCount = 0) => ({ frontEndCount, dataVisCount, backEndCount }) ) - .doOnNext(({ userCount, frontEndCount, dataVisCount, backEndCount }) => { + .doOnNext(({ frontEndCount, dataVisCount, backEndCount }) => { res.render('resources/about', { - userCount, frontEndCount, dataVisCount, backEndCount, diff --git a/server/utils/rx.js b/server/utils/rx.js index 891d24e9f3..20976dfeb8 100644 --- a/server/utils/rx.js +++ b/server/utils/rx.js @@ -1,4 +1,5 @@ -import Rx from 'rx'; +import Rx, { AsyncSubject, Observable } from 'rx'; +import moment from 'moment'; import debugFactory from 'debug'; const debug = debugFactory('fcc:rxUtils'); @@ -31,3 +32,22 @@ export function observeQuery(Model, method, query) { export function observeMethod(context, methodName) { return Rx.Observable.fromNodeCallback(context[methodName], context); } + +// timeChache(amount: Number, unit: String) => Observable +export function timeCache(time, unit) { + const source = this; + let cache; + let expireCacheAt; + return Observable.create(observable => { + // if there is no expire time set + // or if expireCacheAt is smaller than now, + // set new expire time in MS and create new subscription to source + if (!expireCacheAt || expireCacheAt < Date.now()) { + // set expire in ms; + expireCacheAt = moment().add(time, unit).valueOf(); + cache = new AsyncSubject(); + source.subscribe(cache); + } + return cache.subscribe(observable); + }); +} diff --git a/server/views/resources/about.jade b/server/views/resources/about.jade index e0ed846888..c526ee7e24 100644 --- a/server/views/resources/about.jade +++ b/server/views/resources/about.jade @@ -9,14 +9,6 @@ block content span.tag Established: span.text-primary #{daysRunning} | days ago - li - span.tag Population: - span.text-primary #{userCount} - | campers - li - span.tag Completed: - span.text-primary #{globalCompletedCount} - | challenges li.nowrap span.tag Donated: span.text-primary $850,000