Skip to main content

Backup · Restore

The data lake backup comes in two kinds. Choose based on what you lost.

Logical DumpPhysical Backup
Commandpd backup (no arguments)pd backup run …, and a daily systemd timer
WhatPostgreSQL user DB as a SQL file (pg_dump)PostgreSQL via pgBackRest, Cassandra via Medusa — the data files themselves
Where/data1/pp-data/postgres/dump/<db>-YYYYmmdd_HHMMSS.sql/data1/pp-backup/ (pgbackrest/ · medusa/) + log history.jsonl
Restorepd recover <파일>pp one DBpd backup restore … — entire data directory
Full / differential · point-in-time recoveryNone (always full)Yes. PostgreSQL supports point-in-time recovery (PITR) via --target

The backup the timer takes at night and the backup an operator takes with pd backup run pass through the same toolkit (plantpulse-backup) and land in the same history.jsonl. The admin console backup screen runs the same command.

Automatic Backup — Already Enabled

JobWhenWhat
postgres-diffDaily at 01:30PostgreSQL differential
postgres-fullSunday at 01:00PostgreSQL full
cassandra-diffDaily at 01:20Cassandra differential
cassandra-fullSunday at 00:10Cassandra full
purgeSunday at 03:00Clean up per retention policy
docker exec plantpulse-datalake pd backup schedule # 일정 · 마지막 결과 · 다음 실행
docker exec plantpulse-datalake pd backup list # 세트 목록
docker exec plantpulse-datalake pd backup status # 지금 도는 것이 있나

If the LAST column in pd backup schedule is never, it has never run (normal); if it is fail (…), it shows the error from the last run. A Cassandra set with SIZE of - has no size information, but that is not zero. Do not restore from a set where STATUS is error or incomplete.

Change the Schedule

docker exec plantpulse-datalake pd backup schedule set --job postgres-diff --calendar "*-*-* 02:45:00"
docker exec plantpulse-datalake pd backup schedule set --job purge --enabled false
docker exec plantpulse-datalake pd backup schedule reset --job postgres-diff # 그 잡만 기본으로
docker exec plantpulse-datalake pd backup schedule reset # 전부 기본으로

The calendar uses systemd syntax — *-*-* 02:45:00 (daily at 02:45), Sun *-*-* 01:00:00 (Sunday at 01:00), Mon..Fri *-*-* 23:30:00 (weekdays). Invalid expressions are caught in validation and nothing is written. The choice is saved in /data1/pp-data/backup/schedule.json and is reapplied at every startup, even if you recreate the container.

The global switch wins. If you set PP_BACKUP_SCHEDULE_ENABLED=false in the sidecar, the timer only logs «skipped» for every job, regardless of individual settings.

Before Large Operations — Capture One More Snapshot Now

Before upgrades, restores, or configuration changes, capture one more snapshot of this moment.

docker exec plantpulse-datalake pd backup run --engine postgres --type diff
docker exec plantpulse-datalake pd backup run --engine cassandra --type full
docker exec plantpulse-datalake pd backup # 그리고 SQL 사본 하나

Only one runs at a time — if one is running, it rejects with exit 3. Even if the tool exits with 0, if the repository did not grow, it is marked as fail.

Restore — from Physical Backup

Last resort. All writes after that set are lost. This verb enforces a procedure — if you run it without --yes, it refuses and tells you to use --dry-run.

# 1. 세트 고르기 — STATUS 가 ok 인 것만
docker exec plantpulse-datalake pd backup list

# 2. 드라이런 — 전제조건 일곱과 «정확히 무슨 명령이 무엇을 덮어쓸지». 아무것도 안 건드린다
docker exec plantpulse-datalake pd backup restore --engine postgres --set 20260903-013040F_20260904-135107D --dry-run
# preconditions (all pass - ready) 가 나올 때까지 실행하지 않는다

# 3. pp 를 쓰는 서비스를 역순으로 내린다 — storage 는 둔다 (PostgreSQL 은 이 동사가 스스로 멈추고 띄운다)
docker exec plantpulse-datalake pd stop admin-api
docker exec plantpulse-datalake pd stop data-gateway
docker exec plantpulse-datalake pd stop workflow
docker exec plantpulse-datalake pd stop cep
docker exec plantpulse-datalake pd stop timeseries

# 4. 실행
docker exec plantpulse-datalake pd backup restore --engine postgres --set 20260903-013040F_20260904-135107D --yes

# 5. 끝 줄 "done in NNs - restart the dependent services" 를 보고
docker exec plantpulse-datalake pd restart

# 6. 확인
docker exec plantpulse-datalake pd status # 0 STOPPED
docker exec plantpulse-datalake pd backup status # 락이 free
  • Point-in-time recovery (PITR) — PostgreSQL only; you can pass a timestamp like --target "2026-09-04 12:00:00". That set is restored, then WAL is replayed up to that time. If you pass --target to Cassandra, exit 2.
  • Cassandra restore: Medusa stops and starts Cassandra itself. If you choose a differential set, the full set it references is also restored.
  • Does not run on workers. Restore is a master operation; workers follow it.

Restore — from Logical Dump

pp restores one database to a logical dump snapshot. No undo, no dry run — the moment you pass the file name, DROP DATABASE "pp" executes.

ls -l /data1/pp-data/postgres/dump/ # 날짜와 크기를 먼저 눈으로
docker exec -it plantpulse-datalake pd recover # 목록을 찍고 파일 이름을 묻는다 (Ctrl+C 취소)
docker exec plantpulse-datalake pd recover pp-20260904_131500.sql

The procedure is the same as steps 3–6 of physical restore (stop the service first, bring it up after). Even if you load a dump from another database (temporal, hive, kestra), it goes into pp — those databases use physical backup.

Do Not

  • Do not run --yes without --dry-run. A restore you did not see the plan for is a restore where you do not know what point in time you are returning to.
  • Do not restore over a running service. Attached services hold stale sessions and emit errors.
  • Do not manually delete the lock file (/data1/pp-backup/pd-backup.lock). A lock from a dead PID is read as free by pd.
  • Do not copy dumps to /data1/pp-temp. pd clean deletes them.