fix(e12): close what round one broke, and revert two fixes that overreached
Round two of the review loop, on round one's own diff. Two of its findings were regressions the fixes themselves introduced, which is exactly what the loop is for: **A per-user refusal was writing onto a shared row.** MediaAssets are deduped across users, and the generic failure handler puts the message on the asset — right for an upstream failure, wrong for "your storage is full". Two users queuing the same video share one asset, so the first user hitting their cap failed the second user's job with the first one's private reason, telling someone with an empty library to free up space. The refusal now raises `_OwnerRefused`, caught separately: the job fails, the asset goes back to `pending` for whoever else holds it. Pinned by a test that drives `_download` directly — the refusal happens before extraction, so nothing needs stubbing. **The restore scripts restarted the app, undoing the restore.** `docker compose start` re-runs the container command, and that runs `alembic upgrade head` — so on the rollback path this documents as recommended (restore the dump, THEN pin the older tag) the newer image immediately re-applied the migrations the restore had just undone, and on a FAILED restore it put the app back on a half-restored schema. Both are the opposite of why the stop was added. Nothing is restarted automatically now; the scripts say what to run and when, and the docs' snippets say the same. **Reverted rather than patched:** the OnboardingWizard toast (the wizard already renders that failure inline, next to a Retry button — three recoveries for one failure), and `useVerifyEntry`'s "each new link clears the other". The latter blanked the signed-out card's only banner, where nothing renders the reset flag to replace it. The two states are independent again; what changes is that `dismiss` peels ONE layer, which is what the original finding was actually about. Also: `Stats` uses the YouTube helper rather than the bare one, so the route's English 403 detail no longer beats the translated fallback under a Hungarian UI; `urlparse` guarded alongside `.port` (an unclosed bracket raised just as late), the reason renamed `malformed` since "bad port" misdescribes it; three docstrings narrowed to what the code actually does (the worker's byte check is per-job, not an aggregate ledger, and not on the edit path; the redirect residual leaks a reachability oracle, which the note had denied; the invalidation helper does not cover suspend); the pasted Windows recipe wrapped so `throw` can stop it; the bash one-liner's failure branch no longer exits 0; and the tests that were missing for the round-one fixes — the account panel's error paths, the invalidation set, and the shared-asset case above. Gate green: vitest 685, pytest 950.
This commit is contained in:
+5
-5
@@ -12,11 +12,11 @@ $ErrorActionPreference = "Stop"
|
||||
# encoding name", so this script simply failed there.
|
||||
$remote = "/tmp/siftlode-backup.dump"
|
||||
|
||||
# Best-effort cleanup of the in-container dump. Deliberately NOT `docker compose ... 2>$null`: on
|
||||
# Windows PowerShell 5.1 a redirected native stderr becomes an ErrorRecord, and the
|
||||
# $ErrorActionPreference above makes it TERMINATING — so one stray Compose warning would kill the
|
||||
# script here, masking the real diagnostic below or reporting a finished backup as a failure. A
|
||||
# cleanup step must never decide the verdict.
|
||||
# Best-effort cleanup of the in-container dump. The try/catch is the load-bearing part: on Windows
|
||||
# PowerShell 5.1 ANY redirected native stderr (`2>$null` and `2>&1` alike) becomes an ErrorRecord,
|
||||
# and the $ErrorActionPreference above makes it TERMINATING — so one stray Compose warning would
|
||||
# kill the script here, masking the real diagnostic below or reporting a finished backup as a
|
||||
# failure. Do not remove the empty catch. A cleanup step must never decide the verdict.
|
||||
function Remove-RemoteDump($path) {
|
||||
try { docker compose exec -T db rm -f $path 2>&1 | Out-Null } catch { }
|
||||
}
|
||||
|
||||
+26
-19
@@ -11,9 +11,9 @@ $ErrorActionPreference = "Stop"
|
||||
# which corrupts binary on 5.1 and cannot express `-Encoding Byte` at all on 7.
|
||||
$remote = "/tmp/siftlode-restore.dump"
|
||||
|
||||
# See backup.ps1: `2>$null` on a native command is a TERMINATING error under $ErrorActionPreference
|
||||
# = "Stop" on Windows PowerShell 5.1, so a cleanup step could kill the script after the restore
|
||||
# already succeeded — and the obvious next move, re-running the restore, wipes the database again.
|
||||
# See backup.ps1: on Windows PowerShell 5.1 a redirected native stderr is a TERMINATING error under
|
||||
# $ErrorActionPreference = "Stop", so without the catch a cleanup step could kill the script after
|
||||
# the restore already succeeded — and the obvious next move, re-running it, wipes the database again.
|
||||
function Remove-RemoteDump($path) {
|
||||
try { docker compose exec -T db rm -f $path 2>&1 | Out-Null } catch { }
|
||||
}
|
||||
@@ -31,22 +31,29 @@ $cpCode = $LASTEXITCODE
|
||||
if ($cpCode -ne 0) { throw "RESTORE FAILED — could not copy the dump into the container (exit $cpCode)." }
|
||||
|
||||
# Stop the app before dropping its tables. `--clean` DROPs each object in its own transaction, and a
|
||||
# running api (with its scheduler) holds locks that make those DROPs queue behind it — abort the
|
||||
# wait and the database is left half-dropped. It also keeps the app from writing into a schema that
|
||||
# is only partly back. Restarted in `finally`, so a failed restore does not leave the stack down.
|
||||
# running api (with its scheduler) holds locks that make those DROPs queue behind it — abort the wait
|
||||
# and the database is left half-dropped. It also keeps the app from writing into a schema that is
|
||||
# only partly back.
|
||||
#
|
||||
# It is NOT restarted automatically, on purpose. `docker compose start` re-runs the container's
|
||||
# command, and that runs `alembic upgrade head` — which on the documented rollback path (restore a
|
||||
# pre-upgrade dump, THEN pin the older IMAGE_TAG) would immediately re-apply the very migrations the
|
||||
# restore just undid. And on a FAILED restore it would put the app back on a half-restored schema,
|
||||
# which is the second thing the stop exists to prevent. The operator starts it when they are ready.
|
||||
docker compose stop api worker
|
||||
try {
|
||||
docker compose exec -T db pg_restore -U $user -d $dbname --clean --if-exists $remote
|
||||
$restoreCode = $LASTEXITCODE
|
||||
Remove-RemoteDump $remote
|
||||
$stopCode = $LASTEXITCODE
|
||||
if ($stopCode -ne 0) { throw "Could not stop api/worker (exit $stopCode) — refusing to restore while the app may still be writing." }
|
||||
|
||||
# pg_restore exits non-zero for ignorable warnings too (--clean --if-exists on a fresh database
|
||||
# reports every missing object it tried to drop), so a non-zero code is reported as "check this",
|
||||
# not swallowed and not dressed up as success.
|
||||
if ($restoreCode -ne 0) {
|
||||
throw "pg_restore reported errors while restoring $DumpFile (exit $restoreCode) — read the output above before treating this instance as restored."
|
||||
}
|
||||
Write-Output "Restored $DumpFile"
|
||||
} finally {
|
||||
docker compose start api worker | Out-Null
|
||||
docker compose exec -T db pg_restore -U $user -d $dbname --clean --if-exists $remote
|
||||
$restoreCode = $LASTEXITCODE
|
||||
Remove-RemoteDump $remote
|
||||
|
||||
# pg_restore exits non-zero for ignorable warnings too (--clean --if-exists on a fresh database
|
||||
# reports every missing object it tried to drop), so a non-zero code is reported as "check this",
|
||||
# not swallowed and not dressed up as success.
|
||||
if ($restoreCode -ne 0) {
|
||||
Write-Output "api and worker are left STOPPED: the database may be half-restored. Fix the dump and re-run before starting them."
|
||||
throw "pg_restore reported errors while restoring $DumpFile (exit $restoreCode) — read the output above before treating this instance as restored."
|
||||
}
|
||||
Write-Output "Restored $DumpFile"
|
||||
Write-Output "api and worker are stopped. Start them with: docker compose start api worker"
|
||||
|
||||
+13
-5
@@ -23,18 +23,26 @@ DB_NAME="${POSTGRES_DB:-siftlode}"
|
||||
# Stop the app before dropping its tables. `--clean` DROPs each object in its own transaction, and a
|
||||
# running api (with its scheduler) holds locks that make those DROPs queue behind it — abort the wait
|
||||
# and the database is left half-dropped. It also keeps the app from writing into a schema that is
|
||||
# only partly back. The trap restarts it however this script ends, so a failed restore does not leave
|
||||
# the stack down.
|
||||
docker compose stop api worker
|
||||
restart_app() { docker compose start api worker >/dev/null 2>&1 || true; }
|
||||
trap restart_app EXIT
|
||||
# only partly back.
|
||||
#
|
||||
# It is NOT restarted automatically, on purpose. `docker compose start` re-runs the container's
|
||||
# command, and that runs `alembic upgrade head` — which on the documented rollback path (restore a
|
||||
# pre-upgrade dump, THEN pin the older IMAGE_TAG) would immediately re-apply the very migrations the
|
||||
# restore just undid. And on a FAILED restore it would put the app back on a half-restored schema,
|
||||
# which is the second thing the stop exists to prevent. The operator starts it when they are ready.
|
||||
if ! docker compose stop api worker; then
|
||||
echo "Could not stop api/worker — refusing to restore while the app may still be writing." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# pg_restore exits non-zero for ignorable warnings too (--clean --if-exists on a fresh database
|
||||
# reports every missing object it tried to drop), so a non-zero code is reported as "check this",
|
||||
# not swallowed and not dressed up as success.
|
||||
if docker compose exec -T db pg_restore -U "$USER_NAME" -d "$DB_NAME" --clean --if-exists < "$FILE"; then
|
||||
echo "Restored $FILE"
|
||||
echo "api and worker are stopped. Start them with: docker compose start api worker"
|
||||
else
|
||||
echo "pg_restore reported errors while restoring $FILE — read the output above before treating this instance as restored." >&2
|
||||
echo "api and worker are left STOPPED: the database may be half-restored. Fix the dump and re-run before starting them." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user