You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixes nach dem zweiten Dogfood-Restore: Worker starb nach ~160 MB und
wartete 6,5 h auf einen Admin-Besuch, weil der synchrone curl_multi-Pump
den Tick blockieren konnte, bis PHPs Hard-Limit zuschlug.
- download_chunks_parallel() ist jetzt Deadline-bewusst: neuer Parameter
\$deadline_ts, Pump pollt nach jedem curl_multi_select() die Restzeit
und bricht unfertige Handles mit WP_Error('deadline') ab.
- Contiguous-Prefix-Commit im Restore-Tick: erfolgreiche Präfix-Chunks
werden auch bei Teilerfolg auf Platte geschrieben, nur der Rest wird
im nächsten Tick wiederholt. 3/4 fertig = 3/4 gesichert.
- compute_adaptive_limits() skaliert chunk_mb_download jetzt linear mit
dem Tick-Budget: clamp(ceil(tick_time × 0.2), 4, 20). 25-s-Tick → 5 MB
statt bisher starrer 20 MB, die das Tick-Budget sprengten.
- CURLOPT_TIMEOUT gekoppelt an Tick: clamp(tick_time - 3, 15, 90).
- Shutdown-Safety-Net via register_shutdown_function() feuert
spawn_next_tick() nach, falls ein PHP-Fatal den Tick doch killt —
keine 6-h-Lücken mehr, wenn kein Admin auf der Seite ist.
- Admin-Seite zeigt die externe Cron-URL mit Crontab-Beispiel für
Staging-Server ohne Browser-Traffic.
- readme.txt: neuer Abschnitt "Recommended server configuration" —
Plugin läuft ab 30 s max_execution_time, ≥60 s empfohlen, ≥180 s
optimal.
Tests: 61/61 grün. Drei neue Tests für adaptive Chunk-Größe.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+20Lines changed: 20 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
5
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
8
+
## [1.4.2] — 2026-04-17
9
+
10
+
### Fixed
11
+
-**Worker starb nach ~160 MB und wartete 6,5 h auf einen Admin-Besuch**: Im zweiten Dogfood-Restore mit 1.4.1 lieferten die parallelen Batches plötzlich 40–80 MB in 135–180 s (`Langsamer Download-Batch`). Der Pump von `download_chunks_parallel()` war rein synchron — eine 180-s-`CURLOPT_TIMEOUT` konnte den gesamten 25-s-Tick blockieren. Zwei Batches à 140 s sprengten damit das via `@set_time_limit()` gesetzte Budget, PHP schoss den Worker ab, und weil weder `schedule_next_tick()` noch `spawn_next_tick()` je erreicht wurden, blieb die Queue 6,5 h lang stehen — bis zufällig jemand die Admin-Oberfläche öffnete und der Admin-Fallback den Restart auslöste. Der Pump ist jetzt **Deadline-bewusst**: `download_chunks_parallel()` bekommt einen absoluten `deadline_ts`, pollt nach jedem `curl_multi_select()` (max. 0,5 s) die Restzeit und bricht unfertige Handles ab, bevor PHPs Hard-Limit zuschlägt. Abgebrochene Chunks kommen mit `WP_Error('deadline')` zurück und werden sauber verbucht.
12
+
-**Erfolgreiche Chunks wurden bei Batch-Fehlern weggeworfen**: Wenn drei von vier Chunks in ~40 s fertig waren und der vierte nach 140 s in 0 bytes lief, warf der Retry-Pfad alle vier Temp-Files weg und startete bei Offset 0 des Batches neu. 120 MB Traffic umsonst, Worker noch näher am Time-Limit. Jetzt **Contiguous-Prefix-Commit**: der längste lückenlose Präfix erfolgreicher Chunks wird auch bei Teilerfolg an die Zieldatei angehängt, der Offset wandert entsprechend weiter. Nur der Rest (ab dem ersten Fehler-Chunk) wird im nächsten Tick wiederholt. Damit ist gesichtet: selbst wenn 3/4 fertig werden, bleiben 3/4 auf Platte.
13
+
-**Download-Chunk-Größe ignorierte das Tick-Budget**: Der 20-MB-Default aus 1.4.0 war für 250-s-Ticks richtig, aber für einen 25-s-Tick-Budget-Server zu groß — ein 20-MB-Chunk bei beobachteten 0,3–0,6 MB/s durch Cloudflare Tunnel braucht 30–65 s und sprengt den Tick schon alleine. `compute_adaptive_limits()` skaliert die Chunk-Größe jetzt linear mit dem Tick-Budget: `clamp(ceil(tick_time × 0.2), 4, 20)`. 25-s-Tick → 5 MB, 55-s-Tick → 11 MB, 250-s-Tick → 20 MB (Deckel). Die Parallelität verbraucht bei kleineren Chunks auch weniger RAM, sodass bei 256 MB Memory jetzt 7 statt 4 parallele Streams fahren.
14
+
-**`CURLOPT_TIMEOUT` war an Tick-Länge entkoppelt**: Jeder Chunk hatte starre 180 s `CURLOPT_TIMEOUT`, egal wie klein das Tick-Budget war. Jetzt `chunk_timeout = clamp(tick_time - 3, 15, 90)` — bleibt unter Cloudflare Tunnels ~100-s-Fenster und stirbt immer vor dem PHP-Zeitlimit.
15
+
16
+
### Added
17
+
-**Shutdown-Safety-Net gegen PHP-Fatal / Hard-Time-Limit**: `process_restore_tick()` registriert jetzt per `register_shutdown_function()` einen Fallback, der bei einem Fatal-Error (E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR) den Queue-Lock freigibt und `spawn_next_tick()` nachfeuert. Falls der Deadline-aware-Pump mal danebenliegt und PHP den Worker trotzdem killt, wacht der Restore dank des Loopback-Pings wieder auf — nicht erst beim nächsten Admin-Login.
18
+
-**Admin-Seite zeigt externe Cron-URL**: Neues Card-Panel „Externer Worker-Heartbeat" mit der schlüsselgeschützten `admin-ajax.php?action=sbu_cron_ping&key=…`-URL plus Crontab-Beispiel (`*/2 * * * * curl -fsS -o /dev/null …`). Für reine Staging-Umgebungen ohne Browser-Traffic ist das der Holzhammer-Weg, um die Loopback-Kette am Leben zu halten, wenn WP-Cron gar nicht erst feuert.
19
+
20
+
### Changed
21
+
-**`SBU_Seafile_API::download_chunks_parallel()` hat einen neuen optionalen Parameter `$deadline_ts`**: absolute `microtime(true)`-Schwelle. Legacy-Aufrufe mit drei Argumenten funktionieren unverändert (Default 0 deaktiviert die Deadline-Logik). Für Tests ist das Verhalten unverändert, für den Restore-Tick kommt der Wert aus `$tick_start + $lim['tick_time'] - 2`.
22
+
-**Teil-Batches loggen jetzt INFO statt RETRY**: Wenn ein Batch mit Prefix-Commit weiterkommt, steht im Log `Teilweise erfolgreich (N/M Chunks committed, Rest: Grund)` statt eines roten RETRY-Tokens. Spiegelt die Realität besser: es ist ein Vortschritt, kein Fehler.
23
+
24
+
### Konstanten
25
+
-**Neu**: `SBU_DOWNLOAD_CHUNK_MB_MIN=4` (untere Grenze für die adaptive Chunk-Größe).
26
+
-**Geändert**: `SBU_DOWNLOAD_CHUNK_MB_DEFAULT=20` bleibt — ist jetzt explizit nur noch Ceiling (echter Wert aus `compute_adaptive_limits()`).
0 commit comments