backy_rb 0.2.1 → 0.2.2
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 +5 -0
- data/Gemfile.lock +7 -5
- data/backy_rb.gemspec +5 -1
- data/lib/backy/pg_dump.rb +44 -8
- data/lib/backy/pg_restore.rb +1 -1
- data/lib/backy/s3_save.rb +71 -2
- data/lib/backy/version.rb +1 -1
- data/lib/backy_rb.rb +3 -0
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 592cedc95670f4512c65fffebd96358d351153b2821ad2f237be4c32460060ca
|
4
|
+
data.tar.gz: 7055c420d1d2e382abde9f7049de3241648387acaaf124e5d2b8be92de32c9b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d7416f6c12e79d74202e98dca6f66cebb73d5b08cd7615c1966100aa88f288c4d0724361ec0661783124c281618ddba2bb4d65fd51dbab08ad5ddef4906c7a7
|
7
|
+
data.tar.gz: b2e58e94802831d2915c05e77d94dd87f46a789cc841e679083227d6dd0f6be3d9f20c98b374b5efc7a6f6fddfa525255b76e86b7a632388f84727f0e4ae4a53
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
All notable changes to `Backy` will be documented in this file.
|
4
4
|
|
5
5
|
## [Unreleased]
|
6
|
+
|
7
|
+
## [0.2.2] - 2025-01-25
|
8
|
+
### Fixed
|
9
|
+
- Add Ruby 3.4 compatibility fix for ActiveSupport < 7.1
|
10
|
+
|
6
11
|
## [0.2.1] - 2024-06-24
|
7
12
|
### Fixed
|
8
13
|
- Fix bug where `push` is not working because of missing filename
|
data/Gemfile.lock
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
backy_rb (0.2.
|
4
|
+
backy_rb (0.2.2)
|
5
5
|
activerecord (>= 4.0)
|
6
6
|
activesupport (>= 4.0)
|
7
7
|
aws-sdk-s3 (>= 1.117)
|
8
|
+
concurrent-ruby (~> 1.3)
|
8
9
|
pg (~> 1.5)
|
9
10
|
thor (~> 1.2)
|
10
11
|
|
@@ -95,7 +96,7 @@ GEM
|
|
95
96
|
aws-eventstream (~> 1, >= 1.0.2)
|
96
97
|
brakeman (5.4.1)
|
97
98
|
builder (3.2.4)
|
98
|
-
concurrent-ruby (1.
|
99
|
+
concurrent-ruby (1.3.5)
|
99
100
|
crass (1.0.6)
|
100
101
|
date (3.3.3)
|
101
102
|
diff-lcs (1.5.0)
|
@@ -120,6 +121,7 @@ GEM
|
|
120
121
|
marcel (1.0.2)
|
121
122
|
method_source (1.0.0)
|
122
123
|
mini_mime (1.1.2)
|
124
|
+
mini_portile2 (2.8.9)
|
123
125
|
minitest (5.18.0)
|
124
126
|
net-imap (0.3.6)
|
125
127
|
date
|
@@ -131,9 +133,8 @@ GEM
|
|
131
133
|
net-smtp (0.3.3)
|
132
134
|
net-protocol
|
133
135
|
nio4r (2.5.9)
|
134
|
-
nokogiri (1.15.2
|
135
|
-
|
136
|
-
nokogiri (1.15.2-x86_64-linux)
|
136
|
+
nokogiri (1.15.2)
|
137
|
+
mini_portile2 (~> 2.8.2)
|
137
138
|
racc (~> 1.4)
|
138
139
|
parallel (1.22.1)
|
139
140
|
parser (3.2.1.1)
|
@@ -231,6 +232,7 @@ GEM
|
|
231
232
|
PLATFORMS
|
232
233
|
arm64-darwin-22
|
233
234
|
arm64-darwin-23
|
235
|
+
arm64-darwin-24
|
234
236
|
x86_64-linux
|
235
237
|
|
236
238
|
DEPENDENCIES
|
data/backy_rb.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.summary = "Backy is a powerful and user-friendly database backup gem designed specifically for Ruby on Rails applications. It streamlines the backup process, ensuring your data is safe, secure, and easily retrievable. With its versatile features and easy integration, Backy is the go-to solution for Rails developers looking to protect their valuable information."
|
13
13
|
spec.description = "Backy is a comprehensive database backup solution for Ruby on Rails applications, created to help developers manage and safeguard their data with ease. This robust gem offers a wide range of features"
|
14
14
|
spec.homepage = "https://rubynor.com"
|
15
|
-
spec.required_ruby_version = ">= 2.
|
15
|
+
spec.required_ruby_version = ">= 2.5.0"
|
16
16
|
|
17
17
|
spec.metadata["homepage_uri"] = spec.homepage
|
18
18
|
spec.metadata["source_code_uri"] = "https://github.com/rubynor/backy"
|
@@ -43,9 +43,13 @@ Gem::Specification.new do |spec|
|
|
43
43
|
|
44
44
|
spec.add_dependency "activerecord", ">= 4.0"
|
45
45
|
spec.add_dependency "activesupport", ">= 4.0"
|
46
|
+
|
47
|
+
# Note: For Ruby 3.4+ compatibility with ActiveSupport < 7.1,
|
48
|
+
# we include a compatibility fix in lib/backy_rb.rb
|
46
49
|
spec.add_dependency "aws-sdk-s3", ">= 1.117"
|
47
50
|
spec.add_dependency "pg", "~> 1.5"
|
48
51
|
spec.add_dependency "thor", "~> 1.2"
|
52
|
+
spec.add_dependency "concurrent-ruby", "~> 1.3"
|
49
53
|
|
50
54
|
# For more information and examples about making a new gem, check out our
|
51
55
|
# guide at: https://bundler.io/guides/creating_gem.html
|
data/lib/backy/pg_dump.rb
CHANGED
@@ -15,13 +15,15 @@ module Backy
|
|
15
15
|
log_start
|
16
16
|
|
17
17
|
dump_file = nil
|
18
|
+
@replication_resumed = false
|
18
19
|
|
19
20
|
begin
|
20
21
|
handle_replication { dump_file = backup }
|
21
22
|
rescue => e
|
22
23
|
Logger.error("An error occurred during backup: #{e.message}")
|
23
24
|
ensure
|
24
|
-
|
25
|
+
# Only resume if not already resumed (single core path resumes early)
|
26
|
+
log_replication_resume if replica? && pause_replication? && !@replication_resumed
|
25
27
|
end
|
26
28
|
|
27
29
|
dump_file
|
@@ -63,6 +65,7 @@ module Backy
|
|
63
65
|
def log_replication_resume
|
64
66
|
if resume_replication
|
65
67
|
Logger.log("Replication resumed.")
|
68
|
+
@replication_resumed = true
|
66
69
|
else
|
67
70
|
Logger.error("Failed to resume replication. Manual intervention required.")
|
68
71
|
end
|
@@ -70,13 +73,46 @@ module Backy
|
|
70
73
|
|
71
74
|
def plain_text_backup
|
72
75
|
timestamp = current_timestamp
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
76
|
+
temp_dump_file = "#{DUMP_DIR}/#{database}_#{whoami}@#{hostname}_#{timestamp}.sql"
|
77
|
+
dump_file = "#{temp_dump_file}.gz"
|
78
|
+
|
79
|
+
# First, dump the database without compression
|
80
|
+
dump_cmd = "(#{pg_password_env}pg_dump #{pg_credentials} #{database} #{DUMP_CMD_OPTS} > #{temp_dump_file}) 2>&1 >> #{log_file}"
|
81
|
+
|
82
|
+
Logger.log("Dumping database to #{temp_dump_file} ... ")
|
83
|
+
|
84
|
+
if system(dump_cmd)
|
85
|
+
Logger.success("Database dump completed")
|
86
|
+
|
87
|
+
# Resume replication immediately after dump completes
|
88
|
+
if replica? && pause_replication?
|
89
|
+
log_replication_resume
|
90
|
+
end
|
91
|
+
|
92
|
+
# Now compress the dump file
|
93
|
+
Logger.log("Compressing dump file ... ")
|
94
|
+
|
95
|
+
# Check if pigz is available for single-threaded but faster compression
|
96
|
+
if system("which pigz > /dev/null 2>&1")
|
97
|
+
compression_cmd = "pigz -1 < #{temp_dump_file} > #{dump_file}"
|
98
|
+
Logger.log("Using pigz for faster compression")
|
99
|
+
else
|
100
|
+
compression_cmd = "gzip -1 < #{temp_dump_file} > #{dump_file}"
|
101
|
+
end
|
102
|
+
|
103
|
+
if system(compression_cmd)
|
104
|
+
Logger.success("Compression completed")
|
105
|
+
# Remove the uncompressed file
|
106
|
+
FileUtils.rm_f(temp_dump_file)
|
107
|
+
else
|
108
|
+
Logger.error("Compression failed. See #{log_file}")
|
109
|
+
FileUtils.rm_f(temp_dump_file)
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
else
|
113
|
+
Logger.error("Database dump failed. See #{log_file}")
|
114
|
+
return nil
|
115
|
+
end
|
80
116
|
|
81
117
|
dump_file
|
82
118
|
end
|
data/lib/backy/pg_restore.rb
CHANGED
@@ -45,7 +45,7 @@ module Backy
|
|
45
45
|
FileUtils.mkdir_p(dump_dir)
|
46
46
|
|
47
47
|
decompress_cmd = "pigz -p #{Etc.nprocessors} -dc #{file_name} | tar -C #{dump_dir} --strip-components 3 -xf -"
|
48
|
-
restore_cmd = "pg_restore -j #{Etc.nprocessors} -Fd -O -d #{database} #{dump_dir}"
|
48
|
+
restore_cmd = "pg_restore -j #{Etc.nprocessors} -Fd -O #{pg_credentials} -d #{database} #{dump_dir}"
|
49
49
|
|
50
50
|
# Terminate connections and drop/create database
|
51
51
|
terminate_and_recreate_db = "(#{pg_password_env}psql -c \"#{terminate_connection_sql};\" #{pg_credentials} #{database}; #{pg_password_env}dropdb #{pg_credentials} #{database}; #{pg_password_env}createdb #{pg_credentials} #{database}) 2>&1 >> #{log_file}"
|
data/lib/backy/s3_save.rb
CHANGED
@@ -3,6 +3,8 @@ module Backy
|
|
3
3
|
include S3
|
4
4
|
|
5
5
|
DEFAULT_EXPIRE_AFTER = 1.month
|
6
|
+
PART_SIZE = 50 * 1024 * 1024
|
7
|
+
MAX_THREADS = 5
|
6
8
|
|
7
9
|
def initialize(file_name:, key: nil, expire_after: nil)
|
8
10
|
@file_name = file_name
|
@@ -19,8 +21,12 @@ module Backy
|
|
19
21
|
return
|
20
22
|
end
|
21
23
|
|
22
|
-
File.
|
23
|
-
|
24
|
+
file_size = File.size(file_name)
|
25
|
+
|
26
|
+
if file_size < 5 * 1024 * 1024 * 1024
|
27
|
+
upload_simple
|
28
|
+
else
|
29
|
+
upload_multipart
|
24
30
|
end
|
25
31
|
|
26
32
|
puts "done"
|
@@ -29,5 +35,68 @@ module Backy
|
|
29
35
|
private
|
30
36
|
|
31
37
|
attr_reader :file_name, :key, :expires
|
38
|
+
|
39
|
+
def upload_simple
|
40
|
+
puts "Uploading #{file_name} to S3 ... "
|
41
|
+
File.open(file_name, "rb") do |body|
|
42
|
+
s3.put_object(key: key, body: body, bucket: bucket, expires: expires)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def upload_multipart
|
47
|
+
puts "Uploading #{file_name} to S3 (multipart) ... "
|
48
|
+
upload_id = s3.create_multipart_upload(bucket: bucket, key: key, expires: expires).upload_id
|
49
|
+
parts = []
|
50
|
+
mutex = Mutex.new
|
51
|
+
|
52
|
+
file_size = File.size(file_name)
|
53
|
+
total_parts = (file_size.to_f / PART_SIZE).ceil
|
54
|
+
|
55
|
+
part_numbers = (1..total_parts).to_a
|
56
|
+
|
57
|
+
part_numbers.each_slice(MAX_THREADS) do |batch|
|
58
|
+
threads = batch.map do |part_number|
|
59
|
+
Thread.new do
|
60
|
+
start_pos = (part_number - 1) * PART_SIZE
|
61
|
+
end_pos = [start_pos + PART_SIZE, file_size].min
|
62
|
+
|
63
|
+
part_data = nil
|
64
|
+
File.open(file_name, "rb") do |file|
|
65
|
+
file.seek(start_pos)
|
66
|
+
part_data = file.read(end_pos - start_pos)
|
67
|
+
end
|
68
|
+
|
69
|
+
resp = s3.upload_part(
|
70
|
+
bucket: bucket,
|
71
|
+
key: key,
|
72
|
+
upload_id: upload_id,
|
73
|
+
part_number: part_number,
|
74
|
+
body: part_data
|
75
|
+
)
|
76
|
+
|
77
|
+
mutex.synchronize do
|
78
|
+
parts << {etag: resp.etag, part_number: part_number}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
threads.each(&:join)
|
84
|
+
end
|
85
|
+
|
86
|
+
sorted_parts = parts.sort_by { |p| p[:part_number] }
|
87
|
+
|
88
|
+
s3.complete_multipart_upload(
|
89
|
+
bucket: bucket,
|
90
|
+
key: key,
|
91
|
+
upload_id: upload_id,
|
92
|
+
multipart_upload: {
|
93
|
+
parts: sorted_parts
|
94
|
+
}
|
95
|
+
)
|
96
|
+
rescue => e
|
97
|
+
puts "\nError during multipart upload: #{e.message}"
|
98
|
+
s3.abort_multipart_upload(bucket: bucket, key: key, upload_id: upload_id)
|
99
|
+
raise e
|
100
|
+
end
|
32
101
|
end
|
33
102
|
end
|
data/lib/backy/version.rb
CHANGED
data/lib/backy_rb.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backy_rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Kharchenko
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2025-08-25 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -236,6 +236,20 @@ dependencies:
|
|
236
236
|
- - "~>"
|
237
237
|
- !ruby/object:Gem::Version
|
238
238
|
version: '1.2'
|
239
|
+
- !ruby/object:Gem::Dependency
|
240
|
+
name: concurrent-ruby
|
241
|
+
requirement: !ruby/object:Gem::Requirement
|
242
|
+
requirements:
|
243
|
+
- - "~>"
|
244
|
+
- !ruby/object:Gem::Version
|
245
|
+
version: '1.3'
|
246
|
+
type: :runtime
|
247
|
+
prerelease: false
|
248
|
+
version_requirements: !ruby/object:Gem::Requirement
|
249
|
+
requirements:
|
250
|
+
- - "~>"
|
251
|
+
- !ruby/object:Gem::Version
|
252
|
+
version: '1.3'
|
239
253
|
description: Backy is a comprehensive database backup solution for Ruby on Rails applications,
|
240
254
|
created to help developers manage and safeguard their data with ease. This robust
|
241
255
|
gem offers a wide range of features
|
@@ -294,14 +308,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
294
308
|
requirements:
|
295
309
|
- - ">="
|
296
310
|
- !ruby/object:Gem::Version
|
297
|
-
version: 2.
|
311
|
+
version: 2.5.0
|
298
312
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
299
313
|
requirements:
|
300
314
|
- - ">="
|
301
315
|
- !ruby/object:Gem::Version
|
302
316
|
version: '0'
|
303
317
|
requirements: []
|
304
|
-
rubygems_version: 3.
|
318
|
+
rubygems_version: 3.5.22
|
305
319
|
signing_key:
|
306
320
|
specification_version: 4
|
307
321
|
summary: Backy is a powerful and user-friendly database backup gem designed specifically
|