hotswap 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb39bbe01190402e38969b9721794ab4845fd46907a4bfd8d5e21f3cd2cc30dc
4
- data.tar.gz: c948687920739f879999caf87ab23d8baacefbeb8bcd8a008e37976dc0016d39
3
+ metadata.gz: e2313b39ed36d4fd0d236192de9c34f9ac7546984f8a076d474f035abddef947
4
+ data.tar.gz: a7458d108f6d2051a08c89aa3a8357c3cb72ccb892c7669b69d3deeaf1f5abe3
5
5
  SHA512:
6
- metadata.gz: f549bb47a1e79ee364b68cb8e96160f877190d41f8bdf785ea16659d1f7b5aad3bacd052085c588b9b089906d152bc0428098729d5a44b61c7e1cec866680b29
7
- data.tar.gz: daaaf30d063d08ced91ff9249f625a6424d50247e1748f2b75506ce21bf6279fce63a9001adf72649397bcd3d45d375aafa498d4f94d45e2449d05797daba2b7
6
+ metadata.gz: 53ea80ca58d9f342fc04bc51385674ee5b5f8d3dd64a63a18869b5d4fdc81f8ac74c80a6901991d8709d65aeb565d19a5ca3cbeaa19e1a0408ab4ca9ce0dd154
7
+ data.tar.gz: dfbb24c4a439443db7e43d19f65b9964c86505eda6479fa6ec4ca75cba93b25cc619a6d845aa6ca16a822bc187c2f53f8cabdbf66d4ffae98dc9e93682324fbb
@@ -12,6 +12,9 @@ module Hotswap
12
12
 
13
13
  # Push a new database from an IO stream or file path
14
14
  def push(source, stdout: $stdout, stderr: $stderr)
15
+ source_label = source.is_a?(String) ? source : "stdin"
16
+ logger.info "push started: #{source_label} → #{@path}"
17
+
15
18
  input = source.is_a?(String) ? File.open(source, "rb") : source
16
19
 
17
20
  dir = File.dirname(@path)
@@ -19,31 +22,39 @@ module Hotswap
19
22
  begin
20
23
  IO.copy_stream(input, temp)
21
24
  temp.close
25
+ logger.info "received #{File.size(temp.path)} bytes, running integrity check"
22
26
 
23
27
  db = SQLite3::Database.new(temp.path)
24
28
  result = db.execute("PRAGMA integrity_check")
25
29
  db.close
26
30
  unless result == [["ok"]]
31
+ logger.error "integrity check failed for #{source_label}"
27
32
  stderr.write("ERROR: integrity check failed\n")
28
33
  return false
29
34
  end
30
35
 
36
+ logger.info "integrity check passed, acquiring swap lock"
31
37
  stderr.write("Swapping database...\n")
32
38
 
33
39
  Middleware::SWAP_LOCK.synchronize do
34
40
  if defined?(ActiveRecord::Base)
35
41
  ActiveRecord::Base.connection_handler.clear_all_connections!
42
+ logger.info "disconnected ActiveRecord"
36
43
  end
37
44
  File.rename(temp.path, @path)
45
+ logger.info "renamed #{temp.path} → #{@path}"
38
46
  end
39
47
 
40
48
  if defined?(ActiveRecord::Base)
41
49
  ActiveRecord::Base.establish_connection
50
+ logger.info "reconnected ActiveRecord"
42
51
  end
43
52
 
53
+ logger.info "push complete: #{@path}"
44
54
  stdout.write("OK\n")
45
55
  true
46
56
  rescue => e
57
+ logger.error "push failed: #{e.message}"
47
58
  stderr.write("ERROR: #{e.message}\n")
48
59
  false
49
60
  ensure
@@ -54,7 +65,11 @@ module Hotswap
54
65
 
55
66
  # Pull the database to an IO stream or file path
56
67
  def pull(destination, stderr: $stderr)
68
+ dest_label = destination.is_a?(String) ? destination : "stdout"
69
+ logger.info "pull started: #{@path} → #{dest_label}"
70
+
57
71
  unless File.exist?(@path)
72
+ logger.error "database file not found at #{@path}"
58
73
  stderr.write("ERROR: database file not found at #{@path}\n")
59
74
  return false
60
75
  end
@@ -69,20 +84,28 @@ module Hotswap
69
84
  b.finish
70
85
  dst_db.close
71
86
  src_db.close
87
+ logger.info "backup complete: #{File.size(temp.path)} bytes"
72
88
 
73
89
  if destination.is_a?(String)
74
90
  FileUtils.cp(temp.path, destination)
91
+ logger.info "pull complete: #{@path} → #{destination}"
75
92
  stderr.write("OK\n")
76
93
  else
77
94
  File.open(temp.path, "rb") { |f| IO.copy_stream(f, destination) }
95
+ logger.info "pull complete: #{@path} → stdout"
78
96
  end
79
97
  true
80
98
  rescue => e
99
+ logger.error "pull failed: #{e.message}"
81
100
  stderr.write("ERROR: #{e.message}\n")
82
101
  false
83
102
  ensure
84
103
  temp.unlink if temp && File.exist?(temp.path)
85
104
  end
86
105
  end
106
+
107
+ private
108
+
109
+ def logger = Hotswap.logger
87
110
  end
88
111
  end
@@ -2,6 +2,10 @@ module Hotswap
2
2
  class Railtie < Rails::Railtie
3
3
  config.hotswap = ActiveSupport::OrderedOptions.new
4
4
 
5
+ initializer "hotswap.logger" do
6
+ Hotswap.logger = Rails.logger
7
+ end
8
+
5
9
  initializer "hotswap.configure" do |app|
6
10
  # Discover all SQLite databases from Rails config
7
11
  if app.config.hotswap.database_paths
@@ -27,10 +27,15 @@ module Hotswap
27
27
 
28
28
  @thread = Thread.new { accept_loop }
29
29
  @thread.report_on_exception = false
30
+
31
+ logger.info "listening on #{@socket_path}"
32
+ logger.info "stderr socket on #{@stderr_socket_path}"
33
+ logger.info "managing #{Hotswap.databases.size} database(s): #{Hotswap.databases.map(&:path).join(', ')}"
30
34
  self
31
35
  end
32
36
 
33
37
  def stop
38
+ logger.info "shutting down"
34
39
  @server&.close
35
40
  @stderr_server&.close
36
41
  @thread&.kill
@@ -45,6 +50,8 @@ module Hotswap
45
50
 
46
51
  private
47
52
 
53
+ def logger = Hotswap.logger
54
+
48
55
  def accept_loop
49
56
  ios = [@server, @stderr_server]
50
57
  loop do
@@ -75,6 +82,7 @@ module Hotswap
75
82
 
76
83
  def handle_connection(socket)
77
84
  unless IO.select([socket], nil, nil, CONNECTION_TIMEOUT)
85
+ logger.warn "connection timed out"
78
86
  socket.write("ERROR: connection timeout\n") rescue nil
79
87
  return
80
88
  end
@@ -83,6 +91,7 @@ module Hotswap
83
91
  return unless line
84
92
 
85
93
  parts = Shellwords.split(line.strip)
94
+ logger.info "command: #{parts.join(' ')}" unless parts.empty?
86
95
 
87
96
  # Grab the stderr socket if one is waiting
88
97
  stderr_io = take_stderr_client
@@ -94,6 +103,7 @@ module Hotswap
94
103
  stderr: stderr_io || $stderr
95
104
  )
96
105
  rescue => e
106
+ logger.error "connection error: #{e.message}"
97
107
  socket.write("ERROR: #{e.message}\n") rescue nil
98
108
  ensure
99
109
  stderr_io&.close rescue nil
@@ -1,3 +1,3 @@
1
1
  module Hotswap
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
data/lib/hotswap.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "logger"
1
2
  require_relative "hotswap/version"
2
3
  require_relative "hotswap/middleware"
3
4
  require_relative "hotswap/database"
@@ -10,6 +11,11 @@ module Hotswap
10
11
 
11
12
  class << self
12
13
  attr_accessor :socket_path, :stderr_socket_path
14
+ attr_writer :logger
15
+
16
+ def logger
17
+ @logger ||= Logger.new($stdout, progname: "hotswap")
18
+ end
13
19
 
14
20
  def configure
15
21
  yield self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hotswap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Gessler