openvibers/openvibe.report Commits

The shadow job compares one Network answer, taken in first (REP-2) (#91)

OP OpenVibers committed 11 days ago · ac0a26448d · 3 files, +28 −4

The shadow read Network's stats fresh every 15 minutes and compared them with Report's tables from
the last ingest (every 5 minutes). Rolling numbers move between two reads, so 382 of 579 passes in a
week were "differences" (46-58 numbers each: the last 24 hours' requests, today's pageviews) that
were only the clock. Now the job reads Network once, takes that answer in, and compares with it; a
number Report does not reproduce is still a difference. Network's chat counts read 0 at times for a
separate reason, fixed in Network #549.

Changes

ddiff --git a/server/index.js b/server/index.js
iindex ca11857..dc0ae85 100644
---- a/server/index.js
++++ b/server/index.js
@@@ -32,7 +32,7 @@ async function start() {
const { app, ctx } = await createApp();
const { config } = ctx;
-- const jobs = createAnalyticsJobs({ config, analytics: ctx.analytics, shadow: ctx.shadow, log: ctx.log });
++ const jobs = createAnalyticsJobs({ config, analytics: ctx.analytics, shadow: ctx.shadow, network: ctx.network, log: ctx.log });
// The AI meter's job (plan L40/L41): the daily roll-ups, off under drill mode.
const aiUsageJobs = createAiUsageJobs({ config, store: ctx.store, now: ctx.now, log: ctx.log });
const allJobs = { ...jobs, stop: async () => { jobs.stop(); aiUsageJobs.stop(); } };
ddiff --git a/server/jobs/analytics.js b/server/jobs/analytics.js
iindex 457a406..c08791a 100644
---- a/server/jobs/analytics.js
++++ b/server/jobs/analytics.js
@@@ -4,12 +4,14 @@
* The two background jobs (server/index.js starts them; tests never do):
*
* ingest pull Network's open stats into Report's tables every REPORT_INGEST_INTERVAL_MS and at boot
-- * shadow compare the same window from Network and Report every REPORT_SHADOW_INTERVAL_MS and at boot
++ * shadow compare the same window from Network and Report every REPORT_SHADOW_INTERVAL_MS and at boot: one
++ * Network answer is taken in and compared, so a rolling number that moved between two reads (the last
++ * 24 hours' requests, today's pageviews) is not a difference
*
* Neither job runs when REPORT_JOBS=0. A failed pass logs one short line and leaves the last good data in place;
* the next pass retries. Overlapping passes in one process are skipped.
*/
--function createAnalyticsJobs({ config = {}, analytics = null, shadow = null, log = console } = {}) {
++function createAnalyticsJobs({ config = {}, analytics = null, shadow = null, network = null, log = console } = {}) {
const cfg = config.jobs || {};
const timers = [];
let ingestBusy = false;
@@@ -33,7 +35,17 @@ function createAnalyticsJobs({ config = {}, analytics = null, shadow = null, log
if (!shadow || shadowBusy) return null;
shadowBusy = true;
try {
-- const out = await shadow.compare({ days: cfg.shadowWindowDays || 7 });
++ const days = cfg.shadowWindowDays || 7;
++ // One Network answer for both sides: taken in first, then compared. Two reads minutes apart never agree on the
++ // rolling numbers, so most passes were "differences" that were only the clock (11-03: 382 of 579 passes in a
++ // week, 46-58 numbers each, while the equal passes fell between them). A number Report does not reproduce from
++ // that same answer is still a difference.
++ let stats;
++ if (network && typeof network.stats === 'function' && analytics) {
++ stats = await network.stats(days);
++ if (stats) await analytics.ingestStats(stats);
++ }
++ const out = await shadow.compare(stats ? { days, stats } : { days });
if (out && out.status === 'differences') log.warn(`[OpenVibe.Report] shadow: ${out.differences} difference(s) over ${cfg.shadowWindowDays || 7} days`);
return out;
} catch (err) {
ddiff --git a/test/shadow.test.js b/test/shadow.test.js
iindex e74ce61..f5e6335 100644
---- a/test/shadow.test.js
++++ b/test/shadow.test.js
@@@ -43,6 +43,18 @@ const { stats, NOW } = require('./fixtures/analytics');
assert.strictEqual(body.diffs[0].metric, 'pageviews');
});
++ await check('the job compares the one Network answer it took in: a number that moved between two reads is no difference', async () => {
++ const { createAnalyticsJobs } = require('../server/jobs/analytics');
++ let reads = 0;
++ // A rolling number moves on every read, as the last 24 hours' requests and today's pageviews do.
++ const network = { stats: async () => { reads++; const s = JSON.parse(JSON.stringify(stats)); s.totals.pageviews = 300 + reads * 7; return s; } };
++ const jobs = createAnalyticsJobs({ config: { jobs: { shadowWindowDays: 7 } }, analytics: t.ctx.analytics, shadow: t.ctx.shadow, network, log: { warn() {}, error() {} } });
++ const run = await jobs.runShadow();
++ assert.strictEqual(run.status, 'equal', JSON.stringify(run.diffs));
++ assert.strictEqual(reads, 1, 'one read of Network serves both sides');
++ assert.strictEqual(await t.ctx.store.db.value(`SELECT value::int AS v FROM report_metric_windows WHERE metric = 'pageviews' AND scope = 'network' AND window_days = 7`), 307, 'and Report took it in');
++ });
++
await check('a Network that does not answer is a run with no differences, never a clean claim', async () => {
const down = await t.ctx.shadow.compare({ days: 7, stats: null });
assert.strictEqual(down.status, 'network_unavailable');