@@ -9,124 +9,49 @@ def perform
99 ensure_s3_enabled
1010 validate_s3_config
1111
12- handle_s3_errors do
13- # Capture backup context for better error reporting
14- Sentry . with_scope do |scope |
15- scope . set_context ( "backup" , {
16- service : "S3BackupService" ,
17- rails_env : Rails . env ,
18- timestamp : Time . current . iso8601
19- } )
20- end
21-
22- service = get_s3_service
23-
24- # Create temp directory
25- FileUtils . mkdir_p ( temp_dir )
26-
27- # Generate backup filename
28- timestamp = Time . current . strftime ( "%Y-%m-%d" )
29- backup_filename = "database-#{ timestamp } .sqlite3"
30- temp_backup_path = temp_dir . join ( backup_filename )
31- s3_key = "#{ backup_dir } /database-#{ timestamp } .tar.gz"
32-
33- begin
34- # Create SQLite backup
35- log_info "Creating database backup..."
36-
37- # Check if database path exists and is valid
38- unless database_path && File . exist? ( database_path )
39- error_msg = "Database file not found at: #{ database_path } "
40- log_error error_msg
41- Sentry . capture_message ( error_msg , level : "error" )
42- raise error_msg
43- end
44-
45- # Check if sqlite3 command is available
46- unless system ( "which sqlite3 > /dev/null 2>&1" )
47- error_msg = "sqlite3 command not found - required for database backup"
48- log_error error_msg
49- Sentry . capture_message ( error_msg , level : "error" , extra : {
50- environment : Rails . env ,
51- path : ENV [ "PATH" ]
52- } )
53- raise error_msg
54- end
55-
56- # Use array form to prevent command injection
57- unless system ( "sqlite3" , database_path . to_s , ".backup '#{ temp_backup_path } '" , exception : true )
58- error_msg = "Failed to create SQLite backup"
59- Sentry . capture_message ( error_msg , level : "error" , extra : {
60- command : "sqlite3 #{ database_path } .backup '#{ temp_backup_path } '" ,
61- database_path : database_path . to_s ,
62- temp_backup_path : temp_backup_path . to_s
63- } )
64- raise error_msg
65- end
66- log_info "Database backup created successfully"
67-
68- # Compress the backup
69- log_info "Compressing backup..."
70- temp_compressed_path = create_tar_gz ( timestamp )
71- log_info "Backup compressed successfully"
72-
73- # Upload to S3
74- log_info "Uploading to S3 (#{ s3_key } )..."
75- File . open ( temp_compressed_path , "rb" ) do |file |
76- service . upload ( s3_key , file )
77- end
78- log_info "Backup uploaded to S3 successfully"
79-
80- # Clean up old backups
81- log_info "Cleaning up old backups..."
82- deleted_count = cleanup_old_backups ( service )
83- log_info "Deleted #{ deleted_count } old backups" if deleted_count . positive?
84-
85- backup_size_mb = ( File . size ( temp_compressed_path ) / 1024.0 / 1024.0 ) . round ( 2 )
86- log_info "Database backup completed successfully!"
87- log_info "Backup location: #{ s3_key } "
88- log_info "Backup size: #{ backup_size_mb } MB"
89-
90- # Return summary for callers
91- {
92- success : true ,
93- location : s3_key ,
94- size_mb : backup_size_mb ,
95- deleted_count : deleted_count
96- }
97- rescue => e
98- # Report any unexpected errors to Sentry with full context
99- Sentry . capture_exception ( e , extra : {
100- database_path : database_path . to_s ,
101- backup_filename : backup_filename ,
102- s3_key : s3_key ,
103- step : "backup_process"
104- } )
105- raise # Re-raise to let handle_s3_errors deal with it
106- ensure
107- # Clean up temp files
108- FileUtils . rm_f ( temp_backup_path )
109- FileUtils . rm_f ( temp_dir . join ( "database-#{ timestamp } .tar.gz" ) )
110- end
111- end
112- end
113-
114- private
115-
116- # Logging helpers that work for both rake tasks and jobs
117- def log_info ( message )
118- if defined? ( Rails . logger )
119- Rails . logger . info message
120- else
121- warn message
122- end
123- end
124-
125- def log_error ( message )
126- if defined? ( Rails . logger )
127- Rails . logger . error message
128- else
129- warn "❌ #{ message } "
12+ service = get_s3_service
13+ FileUtils . mkdir_p ( temp_dir )
14+
15+ timestamp = Time . current . strftime ( "%Y-%m-%d" )
16+ backup_filename = "database-#{ timestamp } .sqlite3"
17+ temp_backup_path = temp_dir . join ( backup_filename )
18+ s3_key = "#{ backup_dir } /database-#{ timestamp } .tar.gz"
19+
20+ # Create SQLite backup
21+ Rails . logger . info "Creating database backup..."
22+ system ( "sqlite3" , database_path . to_s , ".backup '#{ temp_backup_path } '" , exception : true )
23+ Rails . logger . info "Database backup created successfully"
24+
25+ # Compress the backup
26+ Rails . logger . info "Compressing backup..."
27+ temp_compressed_path = create_tar_gz ( timestamp )
28+ Rails . logger . info "Backup compressed successfully"
29+
30+ # Upload to S3
31+ Rails . logger . info "Uploading to S3 (#{ s3_key } )..."
32+ File . open ( temp_compressed_path , "rb" ) do |file |
33+ service . upload ( s3_key , file )
13034 end
35+ Rails . logger . info "Backup uploaded to S3 successfully"
36+
37+ # Clean up old backups
38+ Rails . logger . info "Cleaning up old backups..."
39+ deleted_count = cleanup_old_backups ( service )
40+ Rails . logger . info "Deleted #{ deleted_count } old backups" if deleted_count . positive?
41+
42+ backup_size_mb = ( File . size ( temp_compressed_path ) / 1024.0 / 1024.0 ) . round ( 2 )
43+ Rails . logger . info "Database backup completed successfully!"
44+ Rails . logger . info "Backup location: #{ s3_key } "
45+ Rails . logger . info "Backup size: #{ backup_size_mb } MB"
46+
47+ {
48+ success : true ,
49+ location : s3_key ,
50+ size_mb : backup_size_mb ,
51+ deleted_count : deleted_count
52+ }
53+ ensure
54+ FileUtils . rm_f ( temp_backup_path ) if defined? ( temp_backup_path )
55+ FileUtils . rm_f ( temp_dir . join ( "database-#{ timestamp } .tar.gz" ) ) if defined? ( timestamp )
13156 end
13257end
0 commit comments