Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project follows [Semantic Versioning](https://semver.org/).

## Unreleased

### Fixed

- Install and enable cron for pgBackRest backup and PostgreSQL log-archive schedules, and fail setup if the scheduler is not active.

## 0.9.8 - 2026-10-02

### Fixed
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ components:
# schedule_incremental: "0 * * * *"
```

pgBackRest setup installs cron, enables it at boot, and checks that it is active.
Backup schedules run only on the primary; configured log-archive schedules run
on each database host.

Run a PITR restore:

```bash
Expand Down
10 changes: 10 additions & 0 deletions lib/active_postgres/components/pgbackrest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,16 @@ def install_on_host(host, create_stanza: true)
else
remove_backup_schedule(host)
end

ensure_scheduler(host)
end

def ensure_scheduler(host)
install_apt_packages(host, 'cron')
ssh_executor.execute_on_host(host) do
execute :sudo, 'systemctl', 'enable', '--now', 'cron'
execute :sudo, 'systemctl', 'is-active', '--quiet', 'cron'
end
end

def setup_backup_schedules(host, pgbackrest_config)
Expand Down
35 changes: 35 additions & 0 deletions test/components/pgbackrest_scheduler_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'test_helper'

class PgBackRestSchedulerTest < Minitest::Test
def test_install_requires_running_cron_after_configuring_primary_and_standby_schedules
[true, false].each do |primary|
host = 'db.example.com'
config = stub_config(primary_host: host, component_config: {
pgbackrest: { repo_type: 'local', schedule_full: '0 2 * * 0' }
})
calls = []
backend = Object.new
backend.define_singleton_method(:execute) { |*args| calls << args }
executor = Object.new
executor.define_singleton_method(:execute_on_host) { |_host, &block| backend.instance_exec(&block) }
executor.define_singleton_method(:upload_file) { |_host, _content, path, **_options| calls << [:upload, path] }
component = ActivePostgres::Components::PgBackRest.new(config, executor, ActivePostgres::Secrets.new(config))
component.define_singleton_method(:upload_template) { |*_args, **_options| nil }

component.send(:install_on_host, host, create_stanza: primary)

cron_install = calls.index { |args| args.include?('apt-get') && args.last == 'cron' }
cron_enable = calls.index([:sudo, 'systemctl', 'enable', '--now', 'cron'])
cron_check = calls.index([:sudo, 'systemctl', 'is-active', '--quiet', 'cron'])
schedule = if primary
calls.index([:upload, '/etc/cron.d/pgbackrest-backup'])
else
calls.index([:sudo, 'rm', '-f', '/etc/cron.d/pgbackrest-backup-incremental'])
end
assert_operator schedule, :<, cron_install
assert_operator cron_install, :<, cron_enable
assert_operator cron_enable, :<, cron_check
refute_includes calls, [:sudo, 'systemctl', 'restart', 'postgresql']
end
end
end
1 change: 1 addition & 0 deletions test/components/pgbackrest_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ def test_install_on_standby_removes_stale_backup_schedules

ssh_executor = Minitest::Mock.new
ssh_executor.expect(:execute_on_host, nil, ['standby.example.com'])
ssh_executor.expect(:execute_on_host, nil, ['standby.example.com'])
secrets = ActivePostgres::Secrets.new(config)
pgbackrest = ActivePostgres::Components::PgBackRest.new(config, ssh_executor, secrets)
calls = []
Expand Down
Loading