Francis
GitHub

Backup and restore

The runtime can export all of its persistent data to a portable file and load it back later, using the backup and restore subcommands. This is useful for disaster recovery, cloning an environment, and migrating between data stores/providers.

A backup contains everything the provider persists:

  • Actor state
  • Alarms, including scheduled jobs
  • Dead-lettered jobs

Ephemeral data (e.g. host registrations and alarm leases) is intentionally left out, since it’s recreated automatically once hosts reconnect.

The format is provider-neutral, so a backup taken from one provider can be restored into a different one (for example, from SQLite into PostgreSQL)

Both subcommands discover their configuration the same way the runtime does (the FRANCIS_CONFIG environment variable, then the well-known paths) and connect to the data store named by provider.connectionString.

Creating a backup#

francis backup -f backup.francis

The -f flag is required and names the destination file. Use -f - to write the backup to stdout instead, which lets you pipe and/or compress it:

# Compress on the fly
francis backup -f - | gzip > backup.francis.gz

Taking a backup is safe against a live (running) cluster.

When running from a container, invoke the subcommand inside it with the config and data store mounted, and redirect stdout on the host:

docker run --rm \
    -v "$(pwd)/config.yaml:/etc/francis/config.yaml:ro" \
    -v francis-data:/data \
    ghcr.io/italypaleale/francis:1 \
    backup -f - \
  > backup.francis

Restoring a backup#

Restore wipes all existing persistent data and then loads the snapshot:

francis restore -f backup.francis

Use -f - to read from stdin:

gunzip -c backup.francis.gz | francis restore -f -

Restore also works against an empty database.

Note: Restore refuses to run while hosts are connected
Restoring underneath live hosts would corrupt running actors, so restore checks the target database for connected hosts first. If any host has reported a health check within the healthCheckDeadline , the command exits with a non-zero status and changes nothing. Stop every host and any runtime replica sharing the database before restoring.

From a container, pass -i so stdin is forwarded:

cat backup.francis \
  | docker run --rm -i \
    -v "$(pwd)/config.yaml:/etc/francis/config.yaml:ro" \
    -v francis-data:/data \
    ghcr.io/italypaleale/francis:1 \
    restore -f -

Migrating between data stores#

Because the backup format is provider-neutral, you can move data between backends by backing up with one connection string and restoring with another. For example, to migrate from SQLite to PostgreSQL:

# Export from the current (SQLite) store
FRANCIS_CONFIG=./sqlite-config.yaml francis backup -f - \
  | FRANCIS_CONFIG=./postgres-config.yaml francis restore -f -

Note: The in-memory provider can’t be backed up from the CLI.

Edit this page on GitHub