# Automated zero-downtime updates

> Atomically replace MMDB files on live production servers without dropping a single lookup.

To update a live `.mmdb` file safely, download to a temporary file on the **same filesystem**, verify the SHA-256 checksum and file header, and atomically replace the live path with `mv -f` (`rename(2)`).

> **Warning:** Never write directly to the live `.mmdb` path while a process has it memory-mapped (`mmap`). Overwriting an active `mmap` region in place can corrupt reads or trigger `SIGBUS`. Atomic `mv` on the same mount keeps existing file descriptors valid until your reader reopens the path.

### Step 1: Create the atomic update script (`/usr/local/bin/ipscope-update`)

```bash /usr/local/bin/ipscope-update
#!/usr/bin/env bash
set -euo pipefail

EDITION="ipscope-complete"
DEST="/var/lib/ipscope/${EDITION}.mmdb"
ETAG="/var/lib/ipscope/${EDITION}.etag"
TMP="$(mktemp /var/lib/ipscope/.${EDITION}.XXXXXX)"
SUM="${TMP}.sha256"
trap 'rm -f "$TMP" "$SUM"' EXIT

STATUS=$(curl -sSL -w "%{http_code}" "https://download.ipscope.io/v1/databases/${EDITION}/latest.mmdb" \
  -H "Authorization: Bearer ${IPSCOPE_KEY}" \
  --etag-compare "$ETAG" --etag-save "$ETAG" \
  -o "$TMP")

if [ "$STATUS" = "304" ]; then
  exit 0
fi

curl -fsSL "https://download.ipscope.io/v1/databases/${EDITION}/latest.mmdb.sha256" \
  -H "Authorization: Bearer ${IPSCOPE_KEY}" -o "$SUM"

awk -v f="$TMP" '{print $1 "  " f}' "$SUM" | sha256sum -c --status -
chmod 0644 "$TMP"
mv -f "$TMP" "$DEST"
```

### Step 2: Schedule with a systemd timer (`RandomizedDelaySec`)

```text /etc/systemd/system/ipscope-update.timer
[Unit]
Description=Update IPScope MMDB database

[Timer]
OnCalendar=*-*-* 04:00:00 UTC
RandomizedDelaySec=30m
Persistent=true

[Install]
WantedBy=timers.target
```
