solid_backup 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +24 -9
- data/lib/solid_backup/backup/api.rb +3 -3
- data/lib/solid_backup/backup/none.rb +4 -4
- data/lib/solid_backup/backup.rb +28 -13
- data/lib/solid_backup/expiration.rb +25 -0
- data/lib/solid_backup/generators/install_generator.rb +2 -1
- data/lib/solid_backup/version.rb +1 -1
- data/lib/solid_backup.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 195e930fb3a17dcfc67ad285b28ccdcd4dd7bcb3fc659a7bc85c4f7e1ab915e6
|
|
4
|
+
data.tar.gz: 1db537f2585f0548b73444e8f3661b811ea040a4ac306ed0a46eae3e9783c544
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ed4aba930756d2f3b32ad5571a5d84095497e9f63b3952f212350258608dc5f2ed0af100d19764d25d69146606560976d38630906bae695412a87c7b0b7befdb
|
|
7
|
+
data.tar.gz: 4189596b8c2468d089306a01d11ce08d3f8dd42e036a0eeb96e2e4837205cd4987011ca8d4102b70708848766140021d32cc19619681ce9c800d270958fbfab7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Solid Backup
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
- `destination` is the directory where backup files will be placed, not a
|
|
6
|
+
%-encoded template.
|
|
7
|
+
- New `expiration:` option can be set to determine backup expiration policy;
|
|
8
|
+
currently only `SolidBackup::Expiration::Age.new(maximum: ...)` and
|
|
9
|
+
`SolidBackup::Expiration::None.new` are supported.
|
|
10
|
+
|
|
3
11
|
## 0.2.2
|
|
4
12
|
|
|
5
13
|
- Don't call `SolidBackup` too early to avoid errors caused by Rails not being
|
data/README.md
CHANGED
|
@@ -28,11 +28,12 @@ will lack backups due to omission. There are three database backup modes:
|
|
|
28
28
|
|
|
29
29
|
Modes other than `SolidBackup::Backup::None` take the following parameters:
|
|
30
30
|
|
|
31
|
-
- `destination` -
|
|
32
|
-
|
|
33
|
-
and be writeable.
|
|
31
|
+
- `destination` - the directory where backup files will be held; it must already
|
|
32
|
+
exist and be writeable.
|
|
34
33
|
- `interval_in_minutes` - the number of minutes to the beginning of the next
|
|
35
34
|
backup after the previous one finished.
|
|
35
|
+
- `expiration` - backup expiration policy; expired backups are automatically
|
|
36
|
+
removed.
|
|
36
37
|
|
|
37
38
|
Additionally, `SolidBackup::Backup::API` takes the following parameters:
|
|
38
39
|
|
|
@@ -52,10 +53,19 @@ SolidBackup.configure do |config|
|
|
|
52
53
|
# Back up the primary database using the SQLite backup API.
|
|
53
54
|
production.backup "primary",
|
|
54
55
|
SolidBackup::Backup::API,
|
|
55
|
-
destination: "storage/backups
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
destination: "storage/backups",
|
|
57
|
+
|
|
58
|
+
# Start the next backup 15 minutes after the previous one.
|
|
59
|
+
interval_in_minutes: 15,
|
|
60
|
+
|
|
61
|
+
# Back up in 100-page increments.
|
|
62
|
+
step: 100,
|
|
63
|
+
|
|
64
|
+
# Wait 0.1 seconds if a lock interrupts a backup step.
|
|
65
|
+
wait: 0.1,
|
|
66
|
+
|
|
67
|
+
# Remove backups older than 30 days.
|
|
68
|
+
expiration: SolidBackup::Expiration::Age.new(maximum: 30.days)
|
|
59
69
|
|
|
60
70
|
# Don't back up the cache database.
|
|
61
71
|
production.backup "cache", SolidBackup::Backup::None
|
|
@@ -63,8 +73,13 @@ SolidBackup.configure do |config|
|
|
|
63
73
|
# Back up the queue database using VACUUM INTO.
|
|
64
74
|
production.backup "queue",
|
|
65
75
|
SolidBackup::Backup::VacuumInto,
|
|
66
|
-
destination: "storage/backups
|
|
67
|
-
|
|
76
|
+
destination: "storage/backups",
|
|
77
|
+
|
|
78
|
+
# Start the next backup 60 minutes after the previous one.
|
|
79
|
+
interval_in_minutes: 60,
|
|
80
|
+
|
|
81
|
+
# Remove backups older than 12 hours.
|
|
82
|
+
expiration: SolidBackup::Expiration::Age.new(maximum: 12.hours)
|
|
68
83
|
end
|
|
69
84
|
end
|
|
70
85
|
```
|
|
@@ -13,9 +13,9 @@ class SolidBackup::Backup::API < SolidBackup::Backup
|
|
|
13
13
|
def do_perform(backup_path)
|
|
14
14
|
with_connection do |connection|
|
|
15
15
|
source = connection.raw_connection
|
|
16
|
-
|
|
16
|
+
target = SQLite3::Database.new(backup_path)
|
|
17
17
|
|
|
18
|
-
backup = SQLite3::Backup.new(
|
|
18
|
+
backup = SQLite3::Backup.new(target, "main", source, "main")
|
|
19
19
|
|
|
20
20
|
loop do
|
|
21
21
|
result = backup.step(step)
|
|
@@ -32,7 +32,7 @@ class SolidBackup::Backup::API < SolidBackup::Backup
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
backup.finish
|
|
35
|
-
|
|
35
|
+
target.close
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
end
|
|
@@ -7,19 +7,19 @@
|
|
|
7
7
|
# - destination and interval_in_minutes - to allow nil values
|
|
8
8
|
class SolidBackup::Backup::None < SolidBackup::Backup
|
|
9
9
|
def initialize(database:)
|
|
10
|
-
super(database:, destination: nil, interval_in_minutes: 0)
|
|
10
|
+
super(database:, destination: nil, interval_in_minutes: 0, expiration: nil)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def tick
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def perform
|
|
17
|
-
end
|
|
18
|
-
|
|
19
16
|
private
|
|
20
17
|
|
|
21
18
|
attr_writer :destination, :interval_in_minutes
|
|
22
19
|
|
|
20
|
+
def perform
|
|
21
|
+
end
|
|
22
|
+
|
|
23
23
|
def do_perform(backup_path)
|
|
24
24
|
end
|
|
25
25
|
end
|
data/lib/solid_backup/backup.rb
CHANGED
|
@@ -4,10 +4,11 @@ module SolidBackup
|
|
|
4
4
|
class Backup
|
|
5
5
|
attr_reader :database
|
|
6
6
|
|
|
7
|
-
def initialize(database:, destination:, interval_in_minutes:)
|
|
7
|
+
def initialize(database:, destination:, interval_in_minutes:, expiration:)
|
|
8
8
|
self.database = database
|
|
9
9
|
self.destination = destination
|
|
10
10
|
self.interval_in_minutes = interval_in_minutes
|
|
11
|
+
self.expiration = expiration
|
|
11
12
|
|
|
12
13
|
reset_countdown
|
|
13
14
|
end
|
|
@@ -19,23 +20,34 @@ module SolidBackup
|
|
|
19
20
|
|
|
20
21
|
if countdown <= 0
|
|
21
22
|
perform
|
|
23
|
+
remove_expired_backups
|
|
22
24
|
reset_countdown
|
|
23
25
|
end
|
|
24
26
|
end
|
|
25
27
|
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
attr_accessor :countdown, :expiration
|
|
31
|
+
attr_writer :database
|
|
32
|
+
attr_reader :destination, :interval_in_minutes
|
|
33
|
+
|
|
26
34
|
def perform
|
|
27
35
|
ActiveSupport::Notifications.instrument("backup.solid_backup", database:) do
|
|
28
36
|
lock do
|
|
29
|
-
do_perform(Time.now.utc.strftime(destination.to_s))
|
|
37
|
+
do_perform(Time.now.utc.strftime((destination / file_name_pattern).to_s))
|
|
30
38
|
end
|
|
31
39
|
end
|
|
32
40
|
end
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
def remove_expired_backups
|
|
43
|
+
files = destination.children.select(&:file?)
|
|
44
|
+
expiration.select_expired(files) do |pathname|
|
|
45
|
+
Time.strptime(pathname.basename.to_s, file_name_pattern)
|
|
46
|
+
rescue ArgumentError
|
|
47
|
+
end.each do |pathname|
|
|
48
|
+
pathname.unlink
|
|
49
|
+
end
|
|
50
|
+
end
|
|
39
51
|
|
|
40
52
|
def interval_in_minutes=(value)
|
|
41
53
|
if !value.is_a?(Integer) || value <= 0
|
|
@@ -49,17 +61,16 @@ module SolidBackup
|
|
|
49
61
|
|
|
50
62
|
def destination=(value)
|
|
51
63
|
value = Pathname(value)
|
|
52
|
-
directory = value.dirname
|
|
53
64
|
|
|
54
|
-
if !
|
|
55
|
-
raise "invalid backup configuration for #{database}: destination directory #{
|
|
65
|
+
if !value.directory?
|
|
66
|
+
raise "invalid backup configuration for #{database}: destination directory #{value} must exist"
|
|
56
67
|
end
|
|
57
68
|
|
|
58
|
-
test_path =
|
|
69
|
+
test_path = value / "solid_backup.txt"
|
|
59
70
|
begin
|
|
60
71
|
test_path.write("Solid Backup Test")
|
|
61
72
|
rescue Errno::EACCES
|
|
62
|
-
raise "invalid backup configuration for #{database}: destination directory #{
|
|
73
|
+
raise "invalid backup configuration for #{database}: destination directory #{value} must be writeable"
|
|
63
74
|
ensure
|
|
64
75
|
test_path.unlink
|
|
65
76
|
end
|
|
@@ -79,10 +90,14 @@ module SolidBackup
|
|
|
79
90
|
ActiveRecord::Base.connection_handler.establish_connection(database.to_sym)
|
|
80
91
|
end
|
|
81
92
|
|
|
93
|
+
def file_name_pattern
|
|
94
|
+
"#{database}_%Y%m%dT%H%M%S.sqlite3"
|
|
95
|
+
end
|
|
96
|
+
|
|
82
97
|
delegate :with_connection, to: :connection_pool
|
|
83
98
|
|
|
84
99
|
def lock
|
|
85
|
-
path = destination
|
|
100
|
+
path = destination / ".solid_backup.#{database}.lock"
|
|
86
101
|
|
|
87
102
|
File.open(path, File::RDWR | File::CREAT) do |f|
|
|
88
103
|
if f.flock(File::LOCK_EX | File::LOCK_NB)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module SolidBackup::Expiration
|
|
2
|
+
class None
|
|
3
|
+
def select_expired(pathnames)
|
|
4
|
+
[]
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class Age
|
|
9
|
+
def initialize(maximum:)
|
|
10
|
+
self.maximum = maximum
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def select_expired(pathnames)
|
|
14
|
+
threshold = maximum.ago
|
|
15
|
+
pathnames.select do |pathname|
|
|
16
|
+
timestamp = yield(pathname)
|
|
17
|
+
timestamp && timestamp < threshold
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
attr_accessor :maximum
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -15,8 +15,9 @@ module SolidBackup
|
|
|
15
15
|
<<~CODE.chomp
|
|
16
16
|
production.backup #{db_config.name.inspect},
|
|
17
17
|
SolidBackup::Backup::API,
|
|
18
|
-
destination: "storage/backups
|
|
18
|
+
destination: "storage/backups",
|
|
19
19
|
interval_in_minutes: 60,
|
|
20
|
+
expiration: SolidBackup::Expiration::Age.new(maximum: 24.hours),
|
|
20
21
|
step: 100,
|
|
21
22
|
wait: 0.1
|
|
22
23
|
CODE
|
data/lib/solid_backup/version.rb
CHANGED
data/lib/solid_backup.rb
CHANGED
|
@@ -6,6 +6,7 @@ require "solid_backup/backup/api"
|
|
|
6
6
|
require "solid_backup/backup/vacuum_into"
|
|
7
7
|
require "solid_backup/configuration"
|
|
8
8
|
require "solid_backup/configuration/environment"
|
|
9
|
+
require "solid_backup/expiration"
|
|
9
10
|
require "solid_backup/version"
|
|
10
11
|
require "solid_backup/railtie"
|
|
11
12
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: solid_backup
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Greg Navis
|
|
@@ -110,6 +110,7 @@ files:
|
|
|
110
110
|
- lib/solid_backup/backup/vacuum_into.rb
|
|
111
111
|
- lib/solid_backup/configuration.rb
|
|
112
112
|
- lib/solid_backup/configuration/environment.rb
|
|
113
|
+
- lib/solid_backup/expiration.rb
|
|
113
114
|
- lib/solid_backup/generators/install_generator.rb
|
|
114
115
|
- lib/solid_backup/railtie.rb
|
|
115
116
|
- lib/solid_backup/version.rb
|