feat: aktualisiere SRS-Logik zur Verwendung von konfigurierbaren Zeitfenstern für die Auswahl und Aktualisierung von Elementen
All checks were successful
Deploy to production / deploy (push) Successful in 2m9s

This commit is contained in:
Torsten Schulz (local)
2026-06-04 13:57:13 +02:00
parent 5cc8dde2f1
commit 4e33c3cb83
3 changed files with 69 additions and 14 deletions

View File

@@ -10,20 +10,25 @@ import { sequelize } from '../utils/sequelize.js';
*/ */
const DRY_RUN = process.env.DRY_RUN !== 'false'; const DRY_RUN = process.env.DRY_RUN !== 'false';
const LOOKBACK_DAYS = parseInt(process.env.LOOKBACK_DAYS || '365', 10);
const WINDOW_SECONDS = parseInt(process.env.WINDOW_SECONDS || '10', 10);
const run = async () => { const run = async () => {
try { try {
await sequelize.authenticate(); await sequelize.authenticate();
console.log('✅ DB connection OK'); console.log('✅ DB connection OK');
// Conservative selector: items created in the last 3 days where next_due_at is within 2 minutes of created_at // Selector: items created in the last LOOKBACK_DAYS where next_due_at is within WINDOW_SECONDS of created_at
const selector = ` const selector = `
SELECT id, item_key, course_id, stage, next_due_at, created_at SELECT id, item_key, course_id, stage, next_due_at, created_at
FROM community.vocab_srs_item FROM community.vocab_srs_item
WHERE created_at >= now() - interval '3 days' WHERE created_at >= now() - interval '${LOOKBACK_DAYS} days'
AND abs(extract(epoch from (next_due_at - created_at))) < 120 AND (
next_due_at = created_at
OR abs(extract(epoch from (next_due_at - created_at))) <= ${WINDOW_SECONDS}
)
ORDER BY created_at ASC ORDER BY created_at ASC
LIMIT 500 LIMIT 1000
`; `;
const recent = await sequelize.query(selector, { type: sequelize.QueryTypes.SELECT }); const recent = await sequelize.query(selector, { type: sequelize.QueryTypes.SELECT });
@@ -31,7 +36,7 @@ const run = async () => {
console.table(recent.slice(0, 20)); console.table(recent.slice(0, 20));
if (recent.length === 0) { if (recent.length === 0) {
console.log('\nNo candidate rows found — nothing to do.'); console.log(`\nNo candidate rows found for lookback ${LOOKBACK_DAYS} days and window ${WINDOW_SECONDS}s — nothing to do.`);
return; return;
} }
@@ -40,8 +45,11 @@ const run = async () => {
const updateQuery = ` const updateQuery = `
UPDATE community.vocab_srs_item UPDATE community.vocab_srs_item
SET next_due_at = date_trunc('day', created_at + interval '1 day') + interval '8 hours' SET next_due_at = date_trunc('day', created_at + interval '1 day') + interval '8 hours'
WHERE created_at >= now() - interval '3 days' WHERE created_at >= now() - interval '${LOOKBACK_DAYS} days'
AND abs(extract(epoch from (next_due_at - created_at))) < 120 AND (
next_due_at = created_at
OR abs(extract(epoch from (next_due_at - created_at))) <= ${WINDOW_SECONDS}
)
RETURNING id, item_key, course_id, stage, next_due_at, created_at; RETURNING id, item_key, course_id, stage, next_due_at, created_at;
`; `;

View File

@@ -0,0 +1,36 @@
-- Plain SQL version of fix-srs-queries.sql for clients that don't support psql meta-commands
-- Configure the two variables below before running (edit them in the file):
-- set lookback_days = 365; set window_seconds = 10;
-- Edit these values as needed
-- Configure the two variables below before running (edit them in the file):
-- set lookback_days = 365; set window_seconds = 10;
-- Preview rows to be changed (edit values in the CTE if needed)
WITH vars AS (
SELECT 365::int AS lookback_days, 10::int AS window_seconds
)
SELECT id, item_key, course_id, stage, next_due_at, created_at
FROM community.vocab_srs_item
WHERE created_at >= now() - make_interval(days => (SELECT lookback_days FROM vars))
AND (
next_due_at = created_at
OR abs(EXTRACT(EPOCH FROM (next_due_at - created_at))) <= (SELECT window_seconds FROM vars)
)
ORDER BY created_at ASC
LIMIT 200;
-- Conservative update: set next_due_at to next calendar day at 08:00
WITH vars AS (
SELECT 365::int AS lookback_days, 10::int AS window_seconds
)
UPDATE community.vocab_srs_item
SET next_due_at = date_trunc('day', created_at + interval '1 day') + interval '8 hours'
WHERE created_at >= now() - make_interval(days => (SELECT lookback_days FROM vars))
AND (
next_due_at = created_at
OR abs(EXTRACT(EPOCH FROM (next_due_at - created_at))) <= (SELECT window_seconds FROM vars)
)
RETURNING id, item_key, course_id, stage, next_due_at, created_at;
-- After running, re-run `node backend/scripts/diag-srs-stats.js` to validate counts.

View File

@@ -1,23 +1,34 @@
-- Fix items that were created with next_due_at ~= created_at (within 2 minutes)
-- Run this after a backup. Adjust the WHERE clause if you want a different window. -- Fix items that were created with next_due_at ~= created_at
-- Run this after a backup. Edit the two variables below to widen/narrow the search.
-- CONFIG: adjust as needed
\set LOOKBACK_DAYS 365
\set WINDOW_SECONDS 10
BEGIN; BEGIN;
-- Preview rows to be changed -- Preview rows to be changed
SELECT id, item_key, course_id, stage, next_due_at, created_at SELECT id, item_key, course_id, stage, next_due_at, created_at
FROM community.vocab_srs_item FROM community.vocab_srs_item
WHERE created_at >= now() - interval '3 days' WHERE created_at >= now() - make_interval(days => :LOOKBACK_DAYS)
AND abs(EXTRACT(EPOCH FROM (next_due_at - created_at))) < 120 AND (
next_due_at = created_at
OR abs(EXTRACT(EPOCH FROM (next_due_at - created_at))) <= :WINDOW_SECONDS
)
ORDER BY created_at ASC ORDER BY created_at ASC
LIMIT 200; LIMIT 200;
-- Conservative update: set next_due_at to next calendar day at 08:00 -- Conservative update: set next_due_at to next calendar day at 08:00
UPDATE community.vocab_srs_item UPDATE community.vocab_srs_item
SET next_due_at = date_trunc('day', created_at + interval '1 day') + interval '8 hours' SET next_due_at = date_trunc('day', created_at + interval '1 day') + interval '8 hours'
WHERE created_at >= now() - interval '3 days' WHERE created_at >= now() - make_interval(days => :LOOKBACK_DAYS)
AND abs(EXTRACT(EPOCH FROM (next_due_at - created_at))) < 120 AND (
next_due_at = created_at
OR abs(EXTRACT(EPOCH FROM (next_due_at - created_at))) <= :WINDOW_SECONDS
)
RETURNING id, item_key, course_id, stage, next_due_at, created_at; RETURNING id, item_key, course_id, stage, next_due_at, created_at;
COMMIT; COMMIT;
-- After running, re-run backend/scripts/diag-srs-stats.js to validate counts. -- After running, re-run `node backend/scripts/diag-srs-stats.js` to validate counts.