mirror of
https://github.com/screentinker/screentinker.git
synced 2026-06-22 05:54:02 -06:00
fix(proof-of-play): throttle play_logs writes to prevent runaway bloat
A player stuck in a tight loop (playlist with 0-second item durations) fires device:play-event 'play_start' ~3x/sec, inserting a play_logs row each time. Three web players doing this generated ~909k rows (99.9% with duration_sec=0) and grew the prod DB to 265 MB. Throttle proof-of-play inserts to at most one per device per 2s (in-memory lastPlayLogAt map). Skipped cycles create no row; the live dashboard progress event still fires every time, so the UI is unaffected. The play_end UPDATE only closes open rows, so throttling play_start is safe. (Junk rows already pruned in prod: 909k deleted, DB 265 MB -> 9.8 MB.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cbe00d6c85
commit
890ec5790f
|
|
@ -18,6 +18,15 @@ const commandQueue = require('../lib/command-queue');
|
||||||
// next checker sweep within heartbeatInterval).
|
// next checker sweep within heartbeatInterval).
|
||||||
const pendingOfflines = new Map();
|
const pendingOfflines = new Map();
|
||||||
const OFFLINE_DEBOUNCE_MS = 5000;
|
const OFFLINE_DEBOUNCE_MS = 5000;
|
||||||
|
|
||||||
|
// Proof-of-play write throttle. A player stuck in a tight loop (e.g. a playlist
|
||||||
|
// with 0-second item durations) fires device:play-event 'play_start' several
|
||||||
|
// times per second; unthrottled this once bloated play_logs to ~900k rows
|
||||||
|
// (~3 inserts/sec from a single web player). Cap proof-of-play inserts to at
|
||||||
|
// most one per device per PLAY_LOG_MIN_GAP_MS. The live dashboard progress
|
||||||
|
// event is still forwarded every time, so the UI is unaffected. In-memory only.
|
||||||
|
const lastPlayLogAt = new Map();
|
||||||
|
const PLAY_LOG_MIN_GAP_MS = 2000;
|
||||||
const { getUserPlan, getUserDeviceCount } = require('../middleware/subscription');
|
const { getUserPlan, getUserDeviceCount } = require('../middleware/subscription');
|
||||||
// Phase 2.3: deviceRoom() resolves a device_id to its workspace room so
|
// Phase 2.3: deviceRoom() resolves a device_id to its workspace room so
|
||||||
// dashboardNs.emit can be scoped instead of broadcast platform-wide.
|
// dashboardNs.emit can be scoped instead of broadcast platform-wide.
|
||||||
|
|
@ -517,10 +526,18 @@ module.exports = function setupDeviceSocket(io) {
|
||||||
if (device_id !== currentDeviceId) return;
|
if (device_id !== currentDeviceId) return;
|
||||||
try {
|
try {
|
||||||
if (event === 'play_start') {
|
if (event === 'play_start') {
|
||||||
|
// Throttle proof-of-play inserts per device so a runaway player
|
||||||
|
// (0-second items) can't flood play_logs. Skipped cycles simply
|
||||||
|
// don't create a row; the dashboard progress event below still fires.
|
||||||
|
const nowMs = Date.now();
|
||||||
|
const lastMs = lastPlayLogAt.get(device_id) || 0;
|
||||||
|
if (nowMs - lastMs >= PLAY_LOG_MIN_GAP_MS) {
|
||||||
|
lastPlayLogAt.set(device_id, nowMs);
|
||||||
db.prepare(`
|
db.prepare(`
|
||||||
INSERT INTO play_logs (device_id, content_id, zone_id, content_name, started_at, trigger_type)
|
INSERT INTO play_logs (device_id, content_id, zone_id, content_name, started_at, trigger_type)
|
||||||
VALUES (?, ?, ?, ?, strftime('%s','now'), 'playlist')
|
VALUES (?, ?, ?, ?, strftime('%s','now'), 'playlist')
|
||||||
`).run(device_id, content_id || null, zone_id || null, content_name || 'Unknown');
|
`).run(device_id, content_id || null, zone_id || null, content_name || 'Unknown');
|
||||||
|
}
|
||||||
// Forward to dashboard so it can render a per-device progress bar.
|
// Forward to dashboard so it can render a per-device progress bar.
|
||||||
// Server-side timestamp avoids clock-skew between player and dashboard.
|
// Server-side timestamp avoids clock-skew between player and dashboard.
|
||||||
emitToDeviceWorkspace(dashboardNs, device_id, 'dashboard:playback-progress', {
|
emitToDeviceWorkspace(dashboardNs, device_id, 'dashboard:playback-progress', {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue