Repository navigation
feat(backup): scheduled server backups to Depot - #15
Merged
Merged
Conversation
Archives the whole game server on a cron schedule and uploads it straight to the minecraft bucket in Depot. The world lives on a ReadWriteOnce volume mounted only into the game server pod, so the plugin is the only party that can read it. Warden mints a presigned upload URL from Depot and hands it over; the archive goes from the game server to object storage directly, through neither Warden nor Depot. Players are warned five minutes before a scheduled backup, ten seconds before a manual one, and again when it starts and finishes. Notices go to Discord and to game chat separately, because the Discord relay ignores bot messages by design. The plugin socket no longer depends on Discord being configured: it now carries Warden's commands as well as chat.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backs the whole game server up on a configurable cron schedule and uploads it to the
minecraftbucket in Depot.How it works
The world lives on a ReadWriteOnce volume mounted only into the
minecraftpod, so Warden cannot read it. The plugin does the archiving: Warden mints a presigned upload URL from Depot and hands it over the existing plugin WebSocket, and the.tar.gzgoes from the game server straight to S3 — through neither Warden nor Depot.Warden ──presign──> Depot ──URL──> Warden ──ws──> plugin ──PUT──> S3 ──> plugin ──> Warden ──complete──> DepotService
warden_backup_jobtracks each run:pending → archiving → uploading → succeeded | failed | timed_out, with size, split archive/upload timings, and the Depot file idwarden_backup_scheduleis a single editable row, so the cron can change without a redeploy. Default0 4 * * *America/Los_Angelesrobfig/cron/v3and the zone is bound into the expression, so 4am stays 4am across a DST shiftpg_advisory_xact_lockaround the check-and-insert plus a unique index onscheduled_forPlugin
tarfile, and a real S3 download — byte-identical, including >100-byte paths and UTF-8 names)BEST_SPEED: region files are already zlib-compressed internally, so the slow levels buy a couple of percent for several times the CPU, and that CPU competes with the tick loopPortal
/backupsis visible to everyone; "Back up now" and the schedule editor are MinecraftAdmins onlyNotifications
Discord and game chat get the warning, the start, and the finish. Note that notices posted to Discord do not reach game chat on their own —
onDiscordMessageignores bot and webhook messages, which is what stops every relayed game line echoing back. So announcements are pushed to both explicitly, with emoji and markdown transliterated for Minecraft's font.Scheduled runs warn at T-5m; "Back up now" warns at T-10s.
Also
The plugin socket no longer requires Discord to be configured. It is now a control channel, not just a chat relay, so
bridge.Start()always serves it and the Discord half is optional.Verified
Ran a full cycle against the dev stack with a simulated game server: warning →
backup_start→ progress → real presigned PUT togr-depot-prod-usw2→ Depot finalize → completion notice with the size Depot reported.Three test files are now in the
minecraftbucket (one 3 MB, two 121 B) underbackups/_pipeline-test/andbackups/2026/10/. Depot files are append-only so I could not remove them.Notes
PRESIGN_EXPIRYis 15m. S3 checksX-Amz-Expiresagainst the request start, not its completion, so a long upload that begins in time is fine — but a game server that cannot start within 15 minutes of the command will fail.http://in the download URL it builds from the request; the client rejoins the path onto the configuredhttps://origin rather than trusting it.