litestream 0.5.1-arm64-darwin → 0.5.2-arm64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -0
- data/lib/litestream/commands.rb +45 -17
- data/lib/litestream/version.rb +1 -1
- data/lib/tasks/litestream_tasks.rake +25 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a40c41f0d36da65b2eb0ce9827ca3e52299f2a0556bb2a21260500e86715834
|
4
|
+
data.tar.gz: 50897df9a669512420e8b46fbb22f96983da8184aeca3b8d26c3998791def81f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b148e0c4d60d82ba6f3d93c1a96e06231fae58dc281bc9c79e0f5dc45c7fbbb303b5b0667a8565502e3e0d83f06b1ea52a576be005ffb7954b9401d3241bb39b
|
7
|
+
data.tar.gz: 45298f6a0c353a52b9515222cb64c28ed592a58f539c6e5e3e30a12722ebfa4663c3a046291ef5d7654d6b6a53bbfc849d863e126a6e7ca9fa1c4aefc34f76e7
|
data/README.md
CHANGED
@@ -165,6 +165,40 @@ You can forward arguments in whatever order you like, you simply need to ensure
|
|
165
165
|
Disables environment variable expansion in configuration file.
|
166
166
|
```
|
167
167
|
|
168
|
+
### Verification
|
169
|
+
|
170
|
+
You can verify the integrity of your backed-up databases using the gem's provided `litestream:verify` rake task. This rake task requires that you specify which specific database you want to verify. As with the `litestream:restore` tasks, you pass arguments to the rake task via argument forwarding. For example, to verify the production database, you would run:
|
171
|
+
|
172
|
+
```shell
|
173
|
+
bin/rails litestream:verify -- --database=storage/production.sqlite3
|
174
|
+
# or
|
175
|
+
bundle exec rake litestream:verify -- --database=storage/production.sqlite3
|
176
|
+
```
|
177
|
+
|
178
|
+
The `litestream:verify` rake task takes the same options as the `litestream:restore` rake task. After restoring the backup, the rake task will verify the integrity of the restored database by ensuring that the restored database file
|
179
|
+
|
180
|
+
1. exists,
|
181
|
+
2. can be opened by SQLite, and
|
182
|
+
3. sufficiently matches the original database file.
|
183
|
+
|
184
|
+
Since point 3 is subjective, the rake task will output a message providing both the file size and number of tables of both the "original" and "restored" databases. You must manually verify that the restored database is within an acceptable range of the original database.
|
185
|
+
|
186
|
+
The rake task will output a message similar to the following:
|
187
|
+
|
188
|
+
```
|
189
|
+
size
|
190
|
+
original 21688320
|
191
|
+
restored 21688320
|
192
|
+
delta 0
|
193
|
+
|
194
|
+
tables
|
195
|
+
original 9
|
196
|
+
restored 9
|
197
|
+
delta 0
|
198
|
+
```
|
199
|
+
|
200
|
+
After restoring the backup, the `litestream:verify` rake task will delete the restored database file. If you need the restored database file, use the `litestream:restore` rake task instead.
|
201
|
+
|
168
202
|
### Introspection
|
169
203
|
|
170
204
|
Litestream offers a handful of commands that allow you to introspect the state of your replication. The gem provides a few rake tasks that wrap these commands for you. For example, you can list the databases that Litestream is configured to replicate:
|
data/lib/litestream/commands.rb
CHANGED
@@ -17,6 +17,9 @@ module Litestream
|
|
17
17
|
# raised when a litestream command requires a database argument but it isn't provided
|
18
18
|
DatabaseRequiredException = Class.new(StandardError)
|
19
19
|
|
20
|
+
# raised when litestream fails to restore a database backup
|
21
|
+
BackupFailedException = Class.new(StandardError)
|
22
|
+
|
20
23
|
class << self
|
21
24
|
def platform
|
22
25
|
[:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-")
|
@@ -73,44 +76,67 @@ module Litestream
|
|
73
76
|
exe_file
|
74
77
|
end
|
75
78
|
|
76
|
-
def replicate(
|
77
|
-
execute("replicate", argv)
|
79
|
+
def replicate(async: true, **argv)
|
80
|
+
execute("replicate", argv, async: async)
|
78
81
|
end
|
79
82
|
|
80
|
-
def restore(database,
|
83
|
+
def restore(database, async: true, **argv)
|
81
84
|
raise DatabaseRequiredException, "database argument is required for restore command, e.g. litestream:restore -- --database=path/to/database.sqlite" if database.nil?
|
82
85
|
|
83
86
|
dir, file = File.split(database)
|
84
87
|
ext = File.extname(file)
|
85
88
|
base = File.basename(file, ext)
|
86
89
|
now = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
90
|
+
backup = File.join(dir, "#{base}-#{now}#{ext}")
|
87
91
|
|
88
92
|
args = {
|
89
|
-
"-o" =>
|
93
|
+
"-o" => backup
|
90
94
|
}.merge(argv)
|
91
95
|
|
92
|
-
execute("restore", args, database)
|
96
|
+
execute("restore", args, database, async: async)
|
97
|
+
|
98
|
+
backup
|
93
99
|
end
|
94
100
|
|
95
|
-
def databases(
|
96
|
-
execute("databases", argv)
|
101
|
+
def databases(async: true, **argv)
|
102
|
+
execute("databases", argv, async: async)
|
97
103
|
end
|
98
104
|
|
99
|
-
def generations(database,
|
105
|
+
def generations(database, async: true, **argv)
|
100
106
|
raise DatabaseRequiredException, "database argument is required for generations command, e.g. litestream:generations -- --database=path/to/database.sqlite" if database.nil?
|
101
107
|
|
102
|
-
execute("generations", argv, database)
|
108
|
+
execute("generations", argv, database, async: async)
|
103
109
|
end
|
104
110
|
|
105
|
-
def snapshots(database,
|
111
|
+
def snapshots(database, async: true, **argv)
|
106
112
|
raise DatabaseRequiredException, "database argument is required for snapshots command, e.g. litestream:snapshots -- --database=path/to/database.sqlite" if database.nil?
|
107
113
|
|
108
|
-
execute("snapshots", argv, database)
|
114
|
+
execute("snapshots", argv, database, async: async)
|
115
|
+
end
|
116
|
+
|
117
|
+
def verify(database, async: true, **argv)
|
118
|
+
raise DatabaseRequiredException, "database argument is required for verify command, e.g. litestream:verify -- --database=path/to/database.sqlite" if database.nil? || !File.exist?(database)
|
119
|
+
|
120
|
+
backup = restore(database, async: false, **argv)
|
121
|
+
|
122
|
+
raise BackupFailedException, "Failed to create backup for validation" unless File.exist?(backup)
|
123
|
+
|
124
|
+
restored_tables_count = `sqlite3 #{backup} "select count(*) from sqlite_schema where type='table';"`.chomp.to_i
|
125
|
+
restored_size = File.size(backup)
|
126
|
+
original_tables_count = `sqlite3 #{database} "select count(*) from sqlite_schema where type='table';"`.chomp.to_i
|
127
|
+
original_size = File.size(database)
|
128
|
+
|
129
|
+
Dir.glob(backup + "*").each { |file| File.delete(file) }
|
130
|
+
|
131
|
+
{
|
132
|
+
size: {original: original_size, restored: restored_size},
|
133
|
+
tables: {original: original_tables_count, restored: restored_tables_count}
|
134
|
+
}
|
109
135
|
end
|
110
136
|
|
111
137
|
private
|
112
138
|
|
113
|
-
def execute(command, argv = {}, database = nil)
|
139
|
+
def execute(command, argv = {}, database = nil, async: true)
|
114
140
|
if Litestream.configuration
|
115
141
|
ENV["LITESTREAM_REPLICA_BUCKET"] ||= Litestream.configuration.replica_bucket
|
116
142
|
ENV["LITESTREAM_ACCESS_KEY_ID"] ||= Litestream.configuration.replica_key_id
|
@@ -121,12 +147,14 @@ module Litestream
|
|
121
147
|
"--config" => Rails.root.join("config", "litestream.yml").to_s
|
122
148
|
}.merge(argv).to_a.flatten.compact
|
123
149
|
cmd = [executable, command, *args, database].compact
|
150
|
+
puts cmd.inspect if ENV["DEBUG"]
|
124
151
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
152
|
+
if async
|
153
|
+
# To release the resources of the Ruby process, just fork and exit.
|
154
|
+
# The forked process executes litestream and replaces itself.
|
155
|
+
exec(*cmd) if fork.nil?
|
156
|
+
else
|
157
|
+
system(*cmd)
|
130
158
|
end
|
131
159
|
end
|
132
160
|
end
|
data/lib/litestream/version.rb
CHANGED
@@ -72,4 +72,29 @@ namespace :litestream do
|
|
72
72
|
|
73
73
|
Litestream::Commands.snapshots(options.delete("--database") || options.delete("-database"), options)
|
74
74
|
end
|
75
|
+
|
76
|
+
desc "verify backup of SQLite database from a Litestream replica, e.g. rake litestream:verify -- -database=storage/production.sqlite3"
|
77
|
+
task verify: :environment do
|
78
|
+
options = {}
|
79
|
+
if (separator_index = ARGV.index("--"))
|
80
|
+
ARGV.slice(separator_index + 1, ARGV.length)
|
81
|
+
.map { |pair| pair.split("=") }
|
82
|
+
.each { |opt| options[opt[0]] = opt[1] || nil }
|
83
|
+
end
|
84
|
+
|
85
|
+
result = Litestream::Commands.verify(options.delete("--database") || options.delete("-database"), options)
|
86
|
+
|
87
|
+
puts <<~TXT if result
|
88
|
+
|
89
|
+
size
|
90
|
+
original #{result[:size][:original]}
|
91
|
+
restored #{result[:size][:restored]}
|
92
|
+
delta #{result[:size][:original] - result[:size][:restored]}
|
93
|
+
|
94
|
+
tables
|
95
|
+
original #{result[:tables][:original]}
|
96
|
+
restored #{result[:tables][:restored]}
|
97
|
+
delta #{result[:tables][:original] - result[:tables][:restored]}
|
98
|
+
TXT
|
99
|
+
end
|
75
100
|
end
|