From 4962399fcf944a9617c4cf0c8b4d47e0d284b54a Mon Sep 17 00:00:00 2001 From: Mike Conrad Date: Tue, 20 May 2025 11:23:17 -0400 Subject: [PATCH] Caching in progress --- app/controllers/replays_controller.ts | 141 ++++++++++++++++---------- 1 file changed, 89 insertions(+), 52 deletions(-) diff --git a/app/controllers/replays_controller.ts b/app/controllers/replays_controller.ts index 2e56a1b..7e6411f 100644 --- a/app/controllers/replays_controller.ts +++ b/app/controllers/replays_controller.ts @@ -21,59 +21,32 @@ interface SentryPagination { } export default class ReplaysController { - public async search({ response }: HttpContext) { - let results = await db.rawQuery(` -SELECT - u.display_name, - u.sessions, - u.total_time_seconds, - u.total_time_readable, - u.average_session_time_readable, - u.average_time_seconds, - r.id AS last_session_id, - r.finished_at AS last_session_time - -FROM ( - -- Aggregate sessions in the last 30 days - SELECT - "user" ->> 'display_name' AS display_name, - COUNT(duration) AS sessions, - SUM(duration) AS total_time_seconds, - AVG(duration) AS average_time_seconds, - CONCAT( - FLOOR(SUM(duration) / 86400), 'd ', - FLOOR(MOD(SUM(duration), 86400) / 3600), 'h ', - FLOOR(MOD(SUM(duration), 3600) / 60), 'm' - ) AS total_time_readable, - CONCAT( - FLOOR(COUNT(duration) / 86400), 'd ', - FLOOR(MOD(COUNT(duration), 86400) / 3600), 'h ', - FLOOR(MOD(COUNT(duration), 3600) / 60), 'm' - ) AS average_session_time_readable - FROM - replays - WHERE - finished_at >= NOW() - INTERVAL '30 days' - GROUP BY - "user" ->> 'display_name' -) u - --- LATERAL JOIN to get latest session (either within 30d or fallback to latest overall) -JOIN LATERAL ( - SELECT id, finished_at - FROM replays - WHERE "user" ->> 'display_name' = u.display_name - ORDER BY - CASE WHEN finished_at >= NOW() - INTERVAL '30 days' THEN 0 ELSE 1 END, - finished_at DESC - LIMIT 1 -) r ON true - -ORDER BY - u.total_time_seconds DESC;` - ) - try { + public async stats({ request, response }: HttpContext) { + const {sendToWebhook} = request.qs() + const cacheKey = `replays:sync:latest_version` + const latestFetchVersion = await redis.get(`replays:fetch:latest_version`) + const latestQueryVersion = await redis.get(`replays:stats:latest_version`) + if (latestFetchVersion == latestQueryVersion) { + let results + results = await redis.get(`replays:sync:version:${latestQueryVersion}:results`) + if (!results) { + console.log('no data in cache, updating') + results = await getResults() + await redis.set(`replays:sync:version:${latestQueryVersion}:results`, JSON.stringify(results)) + } + console.log('resultssdsdfds') + return response.json(results) + } else { + let results = await getResults() + console.log('results quer', latestQueryVersion) + await redis.set(`replays:stats:version:${latestQueryVersion}:results`, JSON.stringify(results)) + await redis.set(`replays:stats:latest_version`, latestFetchVersion) + await redis.set(`replays:fetch:latest_version`, latestFetchVersion) + return response.json(results) + if (sendToWebhook) { + try { + console.log('syncing to webhook') await fetch(env.get('WEBHOOK_URL'), { headers: @@ -87,6 +60,9 @@ ORDER BY } catch(e) { console.error('error sending webhook data', e) } + } + } + response.json(results.rows) } public async list({ request, inertia }: HttpContext) { @@ -136,6 +112,13 @@ ORDER BY queryString = `?start=${start}&end=${end}` } const replays = await fetchBatch(`https://sentry.io/api/0/organizations/${SENTRY_ORG}/replays/${queryString}`) + let latestVersion = await redis.get(`replays:fetch:latest_version`) + if (!latestVersion) { + redis.set('replays:fetch:latest_version', 1) + } else { + redis.set('replays:fetch:latest_version', ++latestVersion) + } + return response.json(replays) } @@ -230,4 +213,58 @@ function buildPaginationLinks(meta: { previousPageUrl: string, lastPage: number; }) return links +} + +async function getResults(){ + let results = await db.rawQuery(` + SELECT + u.display_name, + u.sessions, + u.total_time_seconds, + u.total_time_readable, + u.average_session_time_readable, + u.average_time_seconds, + r.id AS last_session_id, + r.finished_at AS last_session_time + + FROM ( + -- Aggregate sessions in the last 30 days + SELECT + "user" ->> 'display_name' AS display_name, + COUNT(duration) AS sessions, + SUM(duration) AS total_time_seconds, + AVG(duration) AS average_time_seconds, + CONCAT( + FLOOR(SUM(duration) / 86400), 'd ', + FLOOR(MOD(SUM(duration), 86400) / 3600), 'h ', + FLOOR(MOD(SUM(duration), 3600) / 60), 'm' + ) AS total_time_readable, + CONCAT( + FLOOR(COUNT(duration) / 86400), 'd ', + FLOOR(MOD(COUNT(duration), 86400) / 3600), 'h ', + FLOOR(MOD(COUNT(duration), 3600) / 60), 'm' + ) AS average_session_time_readable + FROM + replays + WHERE + finished_at >= NOW() - INTERVAL '30 days' + GROUP BY + "user" ->> 'display_name' + ) u + + -- LATERAL JOIN to get latest session (either within 30d or fallback to latest overall) + JOIN LATERAL ( + SELECT id, finished_at + FROM replays + WHERE "user" ->> 'display_name' = u.display_name + ORDER BY + CASE WHEN finished_at >= NOW() - INTERVAL '30 days' THEN 0 ELSE 1 END, + finished_at DESC + LIMIT 1 + ) r ON true + + ORDER BY + u.total_time_seconds DESC;` + ) + return results } \ No newline at end of file