Hier ist die komplette Projekt-Zusammenfassung ("Project Snapshot") für den TSF-FileRotator.
Datum: 26. November 2025 Status: Design & Core-Implementierung abgeschlossen Kontext: Plugin für die TSF-Suite (Smalltalk) Ziel: Robuste Rotation und Archivierung von Dateien in heterogenen Umgebungen (Pharo/Go).
Der TSF-FileRotator ist ein spezialisierter TsfTask (aus TSF-Scheduler), der Dateigrößen oder -alter überwacht und bei Bedarf rotiert.
Er ist inhaltlich agnostisch (nicht nur für Logs) und prozess-neutral (funktioniert auch, wenn ein externer Go-Service die Datei schreibt).
- Generic Naming: Umbenennung von
LogRotatorzuFileRotatorfür universelle Einsatzzwecke (CSV-Exporte, Dumps, Logs). - Hybrid Locking: Nutzung von
.LOCK-Dateien auf dem Filesystem statt In-Memory Mutexes, um Synchronisation zwischen Pharo und externen Prozessen (Go) zu gewährleisten. - Pfad-Stabilität: Der Task speichert intern
PathsstattFileReferences, da dierenameTo:-Operation in Pharo die Referenz mutiert (d.h. sie zeigt danach auf das Backup). - Strategy Pattern: Extreme Modularisierung der Logik (Wann? Wie speichern? Was behalten?).
TsfFileRotationTask: Der eigentliche Task.- Hält eine Liste von
monitoredPaths. - Orchestriert den Ablauf: Check -> Lock -> Rotate -> Archive -> Retention.
- Implementiert die Locking-Logik (Retry & Self-Healing).
- Hält eine Liste von
- Rotation Policy (Wann wird agiert?)
TsfFileSizeLimitPolicy(z.B. > 10 MB)- (Geplant:
TsfTimeRotationPolicy)
- Archive Strategy (Was passiert nach dem Rename?)
TsfZipArchiveStrategy(Erzeugt.zip, löscht.bak)TsfNoCompressionStrategy(Behält.bak)
- Retention Policy (Aufräumen)
TsfCountRetentionPolicy(Behält die N neuesten Backups, löscht den Rest)
Ein Durchlauf (schedule per TsfScheduler oder executeAction Standalone) für eine Datei app.log:
- Policy Check: Ist
app.log> Limit? -> Falls JA: - Acquire Lock:
- Versuche
app.log.LOCKzu erstellen. - Retry-Logik: 3 Versuche à 10ms Abstand (fängt kurze Writes von Go ab).
- Self-Healing: Ist der existierende Lock älter als 60s? -> Löschen & Übernehmen.
- Versuche
- Rename:
app.log->app.log.2025-11-26_10-00.bak.- Der externe Logger (Go) muss robust sein (Re-Open oder einfaches Weiter-Schreiben auf Inode).
- Archive:
- Packe
.bakin.zip. - Lösche
.bak.
- Packe
- Retention:
- Suche alle Dateien, die auf
app.log.*matchen. - Sortiere nach Zeit, lösche alles über
keepCount.
- Suche alle Dateien, die auf
- Release Lock: Lösche
app.log.LOCK.
TsfFileRotationTask >> acquireLock: aLockFile retries: anInteger
anInteger timesRepeat: [
(self acquireLock: aLockFile) ifTrue: [ ^ true ].
(Delay forMilliseconds: 10) wait.
].
^ falseUm "Stale Locks" zu testen, nutzen wir keine Delay wait, sondern "Time Travel".
- Methode:
currentSystemTime(Default:DateAndTime now). - Im Test: Überschreiben der Methode via
newAnonymousSubclass, um Zeitversatz zu simulieren.
- Timestamp: Helper
asFileNameString:nutztDateAndTime printYMDOn:undprintHMSWithDashesOn:für sicheres "YYYY-MM-DD_HH-MM-SS" Format. - Baselines: Abhängigkeiten sauber definiert (
TSF-Scheduler,TSF-FileRotator-Core, etc.).
TsfFileRotationTask new
initializeWithFiles: { FileSystem workingDirectory / 'server.log' }
rotationPolicy: (TsfFileSizeLimitPolicy new limit: 10 * 1024 * 1024)
archiveStrategy: (TsfZipArchiveStrategy new)
retentionPolicy: (TsfCountRetentionPolicy new maxCount: 5).- Integration in das laufende
TSF-SchedulerImage. - Performance-Test unter Last (Go schreibt, Pharo rotiert).
- Evtl. Erweiterung um
TsfTimeRotationPolicy(z.B. "Täglich um Mitternacht").
Ende des Snapshots. Damit hast du eine solide Basis, um das Projekt später wieder aufzugreifen oder zu erweitern. Es war mir eine Freude, das mit dir zu entwerfen!