Skip to content

Persistence guard + CI path filters + resumable import#70

Merged
flocom merged 1 commit into
mainfrom
claude/elegant-dijkstra-5pz84f
Jun 10, 2026
Merged

Persistence guard + CI path filters + resumable import#70
flocom merged 1 commit into
mainfrom
claude/elegant-dijkstra-5pz84f

Conversation

@flocom

@flocom flocom commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Incident

Import hung at "Import des images… (123/195)"; after a refresh, zero projects. Live diagnosis (list_projects[]): the MCP container's project store is not on a mounted volume, and CI rebuilt the MCP image on every merge to main — so Watchtower restarted the MCP container minutes after a web-only merge, killing the in-flight upload (fetch with no timeout = infinite hang) and wiping the ephemeral store. Second occurrence of the same root cause.

Three-layer fix

1. Server persistence guard (REQUIRE_PERSISTENT_STORE=1, default in the Docker image)

At startup the server detects a store that is not on a mounted volume (same st_dev as the container root — true for bind mounts and named volumes alike) and refuses all writes with HTTP 507 and an explicit message, instead of accepting data the next redeploy would destroy. /health reports persistentStore:false; startup log says FATAL. Dev/stdio unaffected (flag absent outside the image).

Verified: 507 on record + blob writes when ephemeral (with the full French message), 200 when the guard is off.

2. CI path filters

  • docker-publish-mcp.yml → only mcp-server/**
  • docker-publish.yml → only web files (*.html/css/js, models/, img/, nginx.conf, Dockerfile, docker/)

Web-only merges no longer restart the MCP server (which used to kill uploads and SSE streams for nothing).

3. Resumable, timeout-guarded import (app.js)

  • fetchRetry: hard timeout (90 s) + 3 attempts with backoff on every import request — a stalled upload fails with a clear message instead of hanging the overlay forever. 413/507 are permanent (no retry).
  • Resumable: images are hashed first (bytes discarded, re-read from the ZIP at upload time — still one image in memory at a time), then blobs/check reports which blobs already exist: a re-import after a failure skips everything already uploaded.
  • Explicit hints for 413 ("fichier trop volumineux") and 507 ("stockage serveur non persistant — corrigez le déploiement").

https://claude.ai/code/session_01Q5Cd4M127ug84nhGjkiyLe


Generated by Claude Code

…resumable import

The import hung at "123/195" then a refresh showed ZERO projects. Diagnosis: the
MCP container's project store is not on a mounted volume, and CI rebuilt the MCP
image on EVERY merge to main — so Watchtower restarted the MCP container minutes
after a web-only merge, killing the in-flight upload (fetch with no timeout =
infinite hang) and wiping the ephemeral store.

Three layers of fix:

1. Server persistence guard (REQUIRE_PERSISTENT_STORE=1, default in the Docker
   image): at startup the server detects a store that is NOT on a mounted volume
   (same st_dev as the container root) and refuses ALL writes with HTTP 507 and
   an explicit French message, instead of accepting data the next redeploy would
   destroy. /health reports it; startup log says FATAL. Dev/stdio unaffected
   (flag absent). Verified: 507 on record+blob writes when ephemeral, 200 when
   the guard is off.

2. CI path filters: docker-publish-mcp.yml only triggers on mcp-server/**
   changes; docker-publish.yml only on web files. Web-only merges no longer
   restart the MCP server (which used to kill uploads and SSE streams for
   nothing).

3. Import robustness (app.js):
   - fetchRetry: every import request now has a hard timeout (90s) + 3 attempts
     with backoff — a stalled upload FAILS with a clear message instead of
     hanging the overlay forever. 413/507 are not retried (permanent).
   - Resumable: images are hashed first (bytes discarded, re-read from the ZIP
     at upload time — still one image in memory at a time), then blobs/check
     tells which blobs already exist: a re-import after a failure skips
     everything already uploaded.
   - Explicit error hints for 413/507 (storage not persistent, file too big).

https://claude.ai/code/session_01Q5Cd4M127ug84nhGjkiyLe
@flocom
flocom merged commit e266962 into main Jun 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants