fix(scanner): Suchintervall ist ein Takt, keine Pause

`last_scan_at` hielt das ENDE des Laufs fest. Der Scheduler rechnet die
Fälligkeit aber von diesem Wert aus, also kam die Laufzeit von drei bis
vier Minuten jedes Mal obendrauf: bei Einstellung 15 Minuten lagen die
Läufe 19 Minuten auseinander.

Gemessen heute früh, unsere Instanz gegen das Original:

    wir:      07:00  07:19  07:38  07:57  08:16   → 19 Min
    Original: 07:00  07:16  07:31  07:47  08:03   → 15-16 Min

Über das Fenster 07-22 Uhr sind das rund 47 statt 58 Durchgänge pro Tag.
Die Trefferliste der Börsen zeigt nur die neuesten Projekte, jeder
ausgelassene Durchgang kostet deshalb echte Funde.

Jetzt wird der Startzeitpunkt gespeichert. Das `finally` bleibt, damit
sich ein gescheiterter Lauf nicht sofort wiederholt; dauert ein Lauf
länger als das Intervall, ist der nächste sofort fällig - die Sperre aus
demselben Commit verhindert die Überlappung.

Kein Rückschritt zum vorherigen Fehler (e58b94f): der Zeitstempel liegt
weiterhin in der Datenbank und trägt den Zeitplan über Neustarts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sascha Wolf
2026-08-11 11:32:49 +02:00
co-authored by Claude Opus 5
parent 15c94ed49c
commit 9a4266ae7e
3 changed files with 23 additions and 5 deletions
+6 -1
View File
@@ -63,9 +63,14 @@ flowchart TD
S --> F{"Intervall seit<br/>letztem Lauf um?"}
F -->|nein| STOP5["nichts tun"]
F -->|ja| G["Pipeline starten"]
G --> W["last_scan_at schreiben"]
G --> W["last_scan_at = Beginn des Laufs"]
```
Geschrieben wird der **Beginn** des Laufs, nicht sein Ende. Das Intervall ist ein
Takt: mit dem Endzeitpunkt kam die Laufzeit von drei bis vier Minuten jedes Mal
obendrauf, aus 15 Minuten wurden 19 - rund ein Fuenftel weniger Durchgaenge pro
Tag, und die Trefferliste der Boersen zeigt nur die neuesten Projekte.
Die **Sperrfrist** ist die Antwort auf ein konkretes Problem: beide Instanzen
benutzen dieselben Portal-Cookies. Beim ersten Start ziehen sonst beide
gleichzeitig los, was Rate-Limits und CAPTCHAs provoziert - und zwei Chromium
+4 -2
View File
@@ -168,8 +168,10 @@ Zusagen, auf die sich der Rest verlässt:
* `runMatchingPipeline()` läuft **nie zweimal gleichzeitig** und gibt `false`
zurück, wenn schon einer läuft. `isPipelineRunning()` fragt den Zustand ab.
* Der Zeitpunkt landet im `finally` in `settings.last_scan_at` - auch nach einem
Abbruch, damit sich ein gescheiterter Lauf nicht sofort wiederholt.
* Der **Beginn** des Laufs landet im `finally` in `settings.last_scan_at` - im
`finally`, damit sich ein gescheiterter Lauf nicht sofort wiederholt, aber mit
dem Startzeitpunkt, weil das Intervall ein Takt ist und keine Pause zwischen
zwei Läufen. Mit dem Endzeitpunkt wurden aus 15 Minuten 19.
* `cleanup.js` benutzt `sequelize.col('created_at')` statt des Attributnamens:
`Project` benennt die Spalte um, und in `where` greift die Zuordnung nicht.