openvibers/openvibe.zone Commits
Zone: telemetry flushes each minute and keeps 14 days (#17)
Changes
@@@ -68,8 +68,8 @@ async function createApp(opts = {}) {app.locals.metrics = metrics.registry;// Request telemetry (openvibe-sdk/service, plan T1): one aggregated sample per route template, method and status// class each flush, stored in this service's telemetry_samples table; /shared, health, readiness and /metrics make-- // none. server/index.js flushes it on stop and keeps the table to 30 days.-- ctx.telemetry = createHttpTelemetry({ service: 'zone', sink: opts.telemetrySink || createPgTelemetrySink({ db: s.db, log }), skipPrefixes: ['/shared'] });++ // none. server/index.js flushes it on stop and keeps the table to 14 days.++ ctx.telemetry = createHttpTelemetry({ service: 'zone', sink: opts.telemetrySink || createPgTelemetrySink({ db: s.db, log }), skipPrefixes: ['/shared'], intervalMs: 60_000 });app.use(ctx.telemetry.middleware());app.locals.ctx = ctx;const valkey = opts.valkey !== undefined ? opts.valkey : (config.valkey.url ? require('openvibe-sdk/valkey').createValkey({ url: config.valkey.url, prefix: config.valkey.prefix, log }) : null);@@@ -29,11 +29,11 @@ async function start() {console.log(`[OpenVibe.Zone] ${config.nodeEnv} on http://${config.host}:${config.port} → ${config.baseUrl} (db ${ctx.s.db.store})`);});server.keepAliveTimeout = 65_000;-- // telemetry_samples rows older than 30 days go: a minute after start, then daily (openvibe-sdk/telemetry).-- ctx.retention = startTelemetryRetention({ db: ctx.s.db, log: ctx.log || console });++ // telemetry_samples rows older than 14 days go: a minute after start, then daily (openvibe-sdk/telemetry).++ ctx.retention = startTelemetryRetention({ db: ctx.s.db, log: ctx.log || console, olderThanDays: 14 });// The request collector aggregates in memory and has no timer of its own (openvibe-sdk 0.46 createHttpTelemetry):-- // this tick writes each 15-second interval's samples; the stop clears it and flushes once more.-- ctx.telemetryTick = setInterval(() => { ctx.telemetry.flush().catch(() => {}); }, 15_000);++ // this tick writes each minute's samples; the stop clears it and flushes once more.++ ctx.telemetryTick = setInterval(() => { ctx.telemetry.flush().catch(() => {}); }, 60_000);ctx.telemetryTick.unref();ctx.keys.client.start();// The zone job (zone/zones.js tick): pushes what Media has not acknowledged and finishes deletions, every 15 s.@@@ -2,7 +2,7 @@/*** Request telemetry (openvibe-sdk/service, plan T1 step 10): app.js builds one collector for service 'zone' with a* PostgreSQL sink, a page hit five times flushes as ONE aggregated http.request sample (route template, 2xx, count 5),-- * /metrics and /shared files make none, and the 30-day retention deletes only older rows.++ * /metrics and /shared files make none, and the 14-day retention deletes only older rows.*/const assert = require('assert');const { pruneTelemetry } = require('openvibe-sdk/telemetry');@@@ -11,7 +11,7 @@ const fs = require('fs');const path = require('path');(async () => {-- await check('index.js flushes the collector every 15 s and clears that tick before the last flush on stop', () => {++ await check('index.js flushes the collector every minute and clears that tick before the last flush on stop', () => {const index = fs.readFileSync(path.join(__dirname, '..', 'server', 'index.js'), 'utf8');assert.match(index, /ctx\.telemetryTick = setInterval\(\(\) => \{ ctx\.telemetry\.flush\(\)/);assert.match(index, /clearInterval\(ctx\.telemetryTick\); if \(ctx\.retention\) await ctx\.retention\.stop\(\); if \(ctx\.telemetry\) await ctx\.telemetry\.stop\(\);/);@@@ -38,13 +38,13 @@ const path = require('path');assert.deepStrictEqual(requests(), []);});-- await check('the table exists and the retention deletes rows older than 30 days, keeping newer ones', async () => {++ await check('the table exists and the retention deletes rows older than 14 days, keeping newer ones', async () => {const db = t.ctx.s.db;await db.query("DELETE FROM telemetry_samples");const insert = (days) => db.query("INSERT INTO telemetry_samples (at, service, operation) VALUES (now() - make_interval(days => $1), 'zone', 'http.request')", [days]);-- await insert(45);++ await insert(20);await insert(1);-- assert.strictEqual(await pruneTelemetry({ db }), 1);++ assert.strictEqual(await pruneTelemetry({ db, olderThanDays: 14 }), 1);assert.strictEqual((await db.query('SELECT count(*)::int AS n FROM telemetry_samples')).rows[0].n, 1);});} finally { await t.close(); }
@@ -68,8 +68,8 @@ async function createApp(opts = {}) {
@@ -68,8 +68,8 @@ async function createApp(opts = {}) {
app.locals.metrics = metrics.registry;
app.locals.metrics = metrics.registry;
// Request telemetry (openvibe-sdk/service, plan T1): one aggregated sample per route template, method and status
// Request telemetry (openvibe-sdk/service, plan T1): one aggregated sample per route template, method and status
// class each flush, stored in this service's telemetry_samples table; /shared, health, readiness and /metrics make
// class each flush, stored in this service's telemetry_samples table; /shared, health, readiness and /metrics make
- // none. server/index.js flushes it on stop and keeps the table to 30 days.
- ctx.telemetry = createHttpTelemetry({ service: 'zone', sink: opts.telemetrySink || createPgTelemetrySink({ db: s.db, log }), skipPrefixes: ['/shared'] });
+ // none. server/index.js flushes it on stop and keeps the table to 14 days.
+ ctx.telemetry = createHttpTelemetry({ service: 'zone', sink: opts.telemetrySink || createPgTelemetrySink({ db: s.db, log }), skipPrefixes: ['/shared'], intervalMs: 60_000 });
app.use(ctx.telemetry.middleware());
app.use(ctx.telemetry.middleware());
app.locals.ctx = ctx;
app.locals.ctx = ctx;
const valkey = opts.valkey !== undefined ? opts.valkey : (config.valkey.url ? require('openvibe-sdk/valkey').createValkey({ url: config.valkey.url, prefix: config.valkey.prefix, log }) : null);
const valkey = opts.valkey !== undefined ? opts.valkey : (config.valkey.url ? require('openvibe-sdk/valkey').createValkey({ url: config.valkey.url, prefix: config.valkey.prefix, log }) : null);
@@ -29,11 +29,11 @@ async function start() {
@@ -29,11 +29,11 @@ async function start() {
console.log(`[OpenVibe.Zone] ${config.nodeEnv} on http://${config.host}:${config.port} → ${config.baseUrl} (db ${ctx.s.db.store})`);
console.log(`[OpenVibe.Zone] ${config.nodeEnv} on http://${config.host}:${config.port} → ${config.baseUrl} (db ${ctx.s.db.store})`);
});
});
server.keepAliveTimeout = 65_000;
server.keepAliveTimeout = 65_000;
- // telemetry_samples rows older than 30 days go: a minute after start, then daily (openvibe-sdk/telemetry).
- ctx.retention = startTelemetryRetention({ db: ctx.s.db, log: ctx.log || console });
+ // telemetry_samples rows older than 14 days go: a minute after start, then daily (openvibe-sdk/telemetry).
+ ctx.retention = startTelemetryRetention({ db: ctx.s.db, log: ctx.log || console, olderThanDays: 14 });
// The request collector aggregates in memory and has no timer of its own (openvibe-sdk 0.46 createHttpTelemetry):
// The request collector aggregates in memory and has no timer of its own (openvibe-sdk 0.46 createHttpTelemetry):
- // this tick writes each 15-second interval's samples; the stop clears it and flushes once more.
- ctx.telemetryTick = setInterval(() => { ctx.telemetry.flush().catch(() => {}); }, 15_000);
+ // this tick writes each minute's samples; the stop clears it and flushes once more.
+ ctx.telemetryTick = setInterval(() => { ctx.telemetry.flush().catch(() => {}); }, 60_000);
ctx.telemetryTick.unref();
ctx.telemetryTick.unref();
ctx.keys.client.start();
ctx.keys.client.start();
// The zone job (zone/zones.js tick): pushes what Media has not acknowledged and finishes deletions, every 15 s.
// The zone job (zone/zones.js tick): pushes what Media has not acknowledged and finishes deletions, every 15 s.
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
/**
/**
* Request telemetry (openvibe-sdk/service, plan T1 step 10): app.js builds one collector for service 'zone' with a
* Request telemetry (openvibe-sdk/service, plan T1 step 10): app.js builds one collector for service 'zone' with a
* PostgreSQL sink, a page hit five times flushes as ONE aggregated http.request sample (route template, 2xx, count 5),
* PostgreSQL sink, a page hit five times flushes as ONE aggregated http.request sample (route template, 2xx, count 5),
- * /metrics and /shared files make none, and the 30-day retention deletes only older rows.
+ * /metrics and /shared files make none, and the 14-day retention deletes only older rows.
*/
*/
const assert = require('assert');
const assert = require('assert');
const { pruneTelemetry } = require('openvibe-sdk/telemetry');
const { pruneTelemetry } = require('openvibe-sdk/telemetry');
@@ -11,7 +11,7 @@ const fs = require('fs');
@@ -11,7 +11,7 @@ const fs = require('fs');
const path = require('path');
const path = require('path');
(async () => {
(async () => {
- await check('index.js flushes the collector every 15 s and clears that tick before the last flush on stop', () => {
+ await check('index.js flushes the collector every minute and clears that tick before the last flush on stop', () => {
const index = fs.readFileSync(path.join(__dirname, '..', 'server', 'index.js'), 'utf8');
const index = fs.readFileSync(path.join(__dirname, '..', 'server', 'index.js'), 'utf8');
assert.match(index, /ctx\.telemetryTick = setInterval\(\(\) => \{ ctx\.telemetry\.flush\(\)/);
assert.match(index, /ctx\.telemetryTick = setInterval\(\(\) => \{ ctx\.telemetry\.flush\(\)/);
assert.match(index, /clearInterval\(ctx\.telemetryTick\); if \(ctx\.retention\) await ctx\.retention\.stop\(\); if \(ctx\.telemetry\) await ctx\.telemetry\.stop\(\);/);
assert.match(index, /clearInterval\(ctx\.telemetryTick\); if \(ctx\.retention\) await ctx\.retention\.stop\(\); if \(ctx\.telemetry\) await ctx\.telemetry\.stop\(\);/);
@@ -38,13 +38,13 @@ const path = require('path');
@@ -38,13 +38,13 @@ const path = require('path');
assert.deepStrictEqual(requests(), []);
assert.deepStrictEqual(requests(), []);
});
});
- await check('the table exists and the retention deletes rows older than 30 days, keeping newer ones', async () => {
+ await check('the table exists and the retention deletes rows older than 14 days, keeping newer ones', async () => {
const db = t.ctx.s.db;
const db = t.ctx.s.db;
await db.query("DELETE FROM telemetry_samples");
await db.query("DELETE FROM telemetry_samples");
const insert = (days) => db.query("INSERT INTO telemetry_samples (at, service, operation) VALUES (now() - make_interval(days => $1), 'zone', 'http.request')", [days]);
const insert = (days) => db.query("INSERT INTO telemetry_samples (at, service, operation) VALUES (now() - make_interval(days => $1), 'zone', 'http.request')", [days]);
- await insert(45);
+ await insert(20);
await insert(1);
await insert(1);
- assert.strictEqual(await pruneTelemetry({ db }), 1);
+ assert.strictEqual(await pruneTelemetry({ db, olderThanDays: 14 }), 1);
assert.strictEqual((await db.query('SELECT count(*)::int AS n FROM telemetry_samples')).rows[0].n, 1);
assert.strictEqual((await db.query('SELECT count(*)::int AS n FROM telemetry_samples')).rows[0].n, 1);
});
});
} finally { await t.close(); }
} finally { await t.close(); }