litestream 0.11.2 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59bbfcde749c016674729dc5b9b677e56cc5b31ec46727d490a19d481b928d61
4
- data.tar.gz: 87812cd947c281c8212dd4bc414d7aad7e0e70d8d3ff2ffe3c4f07ec31c063fb
3
+ metadata.gz: 97ee67df39c929f752d8b6940cdf73394410faee3a1088d93be18accf45e6a02
4
+ data.tar.gz: d681a3c76f93071531027a341ff2bbaa6cddbe36878fee462425c5618efa848d
5
5
  SHA512:
6
- metadata.gz: 13543423827364cbdb44b83674047549ce88df604017d2fca338a739e9453c097c6fec04aba2bf3621d3f725ced03fa62c20e132671d4e5f47616a1b1bc384b0
7
- data.tar.gz: 52300ad4aa5f5b46026c9dbab2425461b3d68684a3e9cde5a462684366a90714971b3bd53afaa331eaf6fb8a754d78d0c4d6451d9769459cc621fc636de352a2
6
+ metadata.gz: 90604bae936d93428fccc63be8304445c5b8073e6ea63eb4311b45eee5673a0d425ec9b26331eee2b77ad7340f298882b602e968cda850869d075fff709e1dfa
7
+ data.tar.gz: 4315e85e29029800354e50d062e1ef1e91fc6fd590e4df5982605637dd5619d8852d808eb26d362409d7d3750461aec2f66b275629cd4f08952113db9c6b19ce
data/README.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # litestream-ruby
2
2
 
3
+ <p>
4
+ <a href="https://rubygems.org/gems/litestream">
5
+ <img alt="GEM Version" src="https://img.shields.io/gem/v/litestream?color=168AFE&include_prereleases&logo=ruby&logoColor=FE1616">
6
+ </a>
7
+ <a href="https://rubygems.org/gems/litestream">
8
+ <img alt="GEM Downloads" src="https://img.shields.io/gem/dt/litestream?color=168AFE&logo=ruby&logoColor=FE1616">
9
+ </a>
10
+ <a href="https://github.com/testdouble/standard">
11
+ <img alt="Ruby Style" src="https://img.shields.io/badge/style-standard-168AFE?logo=ruby&logoColor=FE1616" />
12
+ </a>
13
+ <a href="https://github.com/fractaledmind/litestream-ruby/actions/workflows/main.yml">
14
+ <img alt="Tests" src="https://github.com/fractaledmind/litestream-ruby/actions/workflows/main.yml/badge.svg" />
15
+ </a>
16
+ <a href="https://github.com/sponsors/fractaledmind">
17
+ <img alt="Sponsors" src="https://img.shields.io/github/sponsors/fractaledmind?color=eb4aaa&logo=GitHub%20Sponsors" />
18
+ </a>
19
+ <a href="https://ruby.social/@fractaledmind">
20
+ <img alt="Ruby.Social Follow" src="https://img.shields.io/mastodon/follow/109291299520066427?domain=https%3A%2F%2Fruby.social&label=%40fractaledmind&style=social">
21
+ </a>
22
+ <a href="https://twitter.com/fractaledmind">
23
+ <img alt="Twitter Follow" src="https://img.shields.io/twitter/url?label=%40fractaledmind&style=social&url=https%3A%2F%2Ftwitter.com%2Ffractaledmind">
24
+ </a>
25
+ </p>
26
+
3
27
  [Litestream](https://litestream.io/) is a standalone streaming replication tool for SQLite. This gem provides a Ruby interface to Litestream.
4
28
 
5
29
  ## Installation
@@ -28,10 +52,10 @@ This gem wraps the standalone executable version of the [Litestream](https://lit
28
52
 
29
53
  Supported platforms are:
30
54
 
31
- * arm64-darwin (macos-arm64)
32
- * x86_64-darwin (macos-x64)
33
- * arm64-linux (linux-arm64)
34
- * x86_64-linux (linux-x64)
55
+ - arm64-darwin (macos-arm64)
56
+ - x86_64-darwin (macos-x64)
57
+ - arm64-linux (linux-arm64)
58
+ - x86_64-linux (linux-x64)
35
59
 
36
60
  ### Using a local installation of `litestream`
37
61
 
@@ -39,13 +63,13 @@ If you are not able to use the vendored standalone executables (for example, if
39
63
 
40
64
  For example, if you've installed `litestream` so that the executable is found at `/usr/local/bin/litestream`, then you should set your environment variable like so:
41
65
 
42
- ``` sh
66
+ ```sh
43
67
  LITESTREAM_INSTALL_DIR=/usr/local/bin
44
68
  ```
45
69
 
46
70
  This also works with relative paths. If you've installed into your app's directory at `./.bin/litestream`:
47
71
 
48
- ``` sh
72
+ ```sh
49
73
  LITESTREAM_INSTALL_DIR=.bin
50
74
  ```
51
75
 
@@ -71,11 +95,12 @@ dbs:
71
95
  The gem also provides a default initializer file at `config/initializers/litestream.rb` that allows you to configure these four environment variables referenced in the configuration file in Ruby. By providing a Ruby interface to these environment variables, you can use any method of storing secrets that you prefer. For example, the default generated file uses Rails' encrypted credentials to store your secrets:
72
96
 
73
97
  ```ruby
74
- litestream_credentials = Rails.application.credentials.litestream
75
- Litestream.configure do |config|
76
- config.replica_bucket = litestream_credentials.replica_bucket
77
- config.replica_key_id = litestream_credentials.replica_key_id
78
- config.replica_access_key = litestream_credentials.replica_access_key
98
+ Rails.application.configure do
99
+ litestream_credentials = Rails.application.credentials.litestream
100
+
101
+ config.litestream.replica_bucket = litestream_credentials&.replica_bucket
102
+ config.litestream.replica_key_id = litestream_credentials&.replica_key_id
103
+ config.litestream.replica_access_key = litestream_credentials&.replica_access_key
79
104
  end
80
105
  ```
81
106
 
@@ -203,6 +228,119 @@ In order to verify that the backup for that database is both restorable and fres
203
228
 
204
229
  After restoring the backup, the `Litestream.verify!` method will delete the restored database file. If you need the restored database file, use the `litestream:restore` rake task or `Litestream::Commands.restore` method instead.
205
230
 
231
+ ### Dashboard
232
+
233
+ The gem provides a web dashboard for monitoring the status of your Litestream replication. To mount the dashboard in your Rails application, add the following to your `config/routes.rb` file:
234
+
235
+ ```ruby
236
+ authenticate :user, -> (user) { user.admin? } do
237
+ mount Litestream::Engine, at: "/litestream"
238
+ end
239
+ ```
240
+
241
+ > [!NOTE]
242
+ > Be sure to [secure the dashboard](#authentication) in production.
243
+
244
+ #### Authentication
245
+
246
+ Litestream Rails does not restrict access out of the box. You must secure the dashboard yourself. However, it does provide basic HTTP authentication that can be used with basic authentication or Devise. All you need to do is setup a username and password.
247
+
248
+ There are two ways to setup a username and password. First, you can use the `LITESTREAM_USERNAME` and `LITESTREAM_PASSWORD` environment variables:
249
+
250
+ ```ruby
251
+ ENV["LITESTREAM_USERNAME"] = "frodo"
252
+ ENV["LITESTREAM_PASSWORD"] = "ikeptmysecrets"
253
+ ```
254
+
255
+ Second, you can configure the access credentials via the Rails configuration object, under the `litestream` key, in an initializer:
256
+
257
+ ```ruby
258
+ # Set authentication credentials for Litestream
259
+ config.litestream.username = Rails.application.credentials.litestream.username
260
+ config.litestream.password = Rails.application.credentials.litestream.password
261
+ ```
262
+
263
+ Either way, if you have set a username and password, Litestream will use basic HTTP authentication.
264
+
265
+ > [!IMPORTANT]
266
+ > If you have not set a username and password, Litestream will not require any authentication to view the dashboard.
267
+
268
+ If you use Devise for authentication in your app, you can also restrict access to the dashboard by using their `authenticate` constraint in your routes file:
269
+
270
+ ```ruby
271
+ authenticate :user, -> (user) { user.admin? } do
272
+ mount LitestreamRails::Engine, at: "/litestream"
273
+ end
274
+ ```
275
+
276
+ ### Examples
277
+
278
+ There is only one screen in the dashboard.
279
+
280
+ - the show view of the Litestream replication process:
281
+
282
+ ![screenshot of the single page in the web dashboard, showing details of the Litestream replication process](images/show-screenshot.png)
283
+
284
+ ### Usage with API-only Applications
285
+
286
+ If your Rails application is an API-only application (generated with the `rails new --api` command), you will need to add the following middleware to your `config/application.rb` file in order to use the dashboard UI provided by Litestream:
287
+
288
+ ```ruby
289
+ # /config/application.rb
290
+ config.middleware.use ActionDispatch::Cookies
291
+ config.middleware.use ActionDispatch::Session::CookieStore
292
+ config.middleware.use ActionDispatch::Flash
293
+ ```
294
+
295
+ ### Overwriting the views
296
+
297
+ You can find the views in [`app/views`](https://github.com/fractaledmind/litestream/tree/main/app/views).
298
+
299
+ ```bash
300
+ app/views/
301
+ ├── layouts
302
+ │   └── litestream
303
+ │   ├── _style.html
304
+ │   └── application.html.erb
305
+ └── litestream
306
+ └── processes
307
+    └── show.html.erb
308
+ ```
309
+
310
+ You can always take control of the views by creating your own views and/or partials at these paths in your application. For example, if you wanted to overwrite the application layout, you could create a file at `app/views/layouts/litestream/application.html.erb`. If you wanted to remove the footer and the automatically disappearing flash messages, as one concrete example, you could define that file as:
311
+
312
+ ```erb
313
+ <!DOCTYPE html>
314
+ <html>
315
+ <head>
316
+ <title>Litestream</title>
317
+ <%= csrf_meta_tags %>
318
+ <%= csp_meta_tag %>
319
+
320
+ <%= render "layouts/litestream/style" %>
321
+ </head>
322
+ <body class="h-full flex flex-col">
323
+ <main class="container mx-auto max-w-4xl mt-4 px-2 grow">
324
+ <%= content_for?(:content) ? yield(:content) : yield %>
325
+ </main>
326
+
327
+ <div class="fixed top-0 left-0 right-0 text-center py-2">
328
+ <% if notice.present? %>
329
+ <p class="py-2 px-3 bg-green-50 text-green-500 font-medium rounded-lg inline-block">
330
+ <%= notice %>
331
+ </p>
332
+ <% end %>
333
+
334
+ <% if alert.present? %>
335
+ <p class="py-2 px-3 bg-red-50 text-red-500 font-medium rounded-lg inline-block">
336
+ <%= alert %>
337
+ </p>
338
+ <% end %>
339
+ </div>
340
+ </body>
341
+ </html>
342
+ ```
343
+
206
344
  ### Introspection
207
345
 
208
346
  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:
@@ -231,7 +369,7 @@ name generation lag start end
231
369
  s3 a295b16a796689f3 -156ms 2024-04-17T00:01:19Z 2024-04-17T00:01:19Z
232
370
  ```
233
371
 
234
- Finally, you can list the snapshots available for a database:
372
+ You can list the snapshots available for a database:
235
373
 
236
374
  ```shell
237
375
  bin/rails litestream:snapshots -- --database=storage/production.sqlite3
@@ -244,6 +382,19 @@ replica generation index size created
244
382
  s3 a295b16a796689f3 1 4645465 2024-04-17T00:01:19Z
245
383
  ```
246
384
 
385
+ Finally, you can list the wal files available for a database:
386
+
387
+ ```shell
388
+ bin/rails litestream:wal -- --database=storage/production.sqlite3
389
+ ```
390
+
391
+ This command lists wal files available for that specified database:
392
+
393
+ ```
394
+ replica generation index offset size created
395
+ s3 a295b16a796689f3 1 0 2036 2024-04-17T00:01:19Z
396
+ ```
397
+
247
398
  ### Running commands from Ruby
248
399
 
249
400
  In addition to the provided rake tasks, you can also run Litestream commands directly from Ruby. The gem provides a `Litestream::Commands` module that wraps the Litestream CLI commands. This is particularly useful for the introspection commands, as you can use the output in your Ruby code.
@@ -269,7 +420,14 @@ Litestream::Commands.snapshots('storage/production.sqlite3')
269
420
  # => [{"replica"=>"s3", "generation"=>"5f4341bc3d22d615", "index"=>"0", "size"=>"4645465", "created"=>"2024-04-17T19:48:09Z"}]
270
421
  ```
271
422
 
272
- You can also restore a database programatically using the `Litestream::Commands.restore` method, which returns the path to the restored database:
423
+ The `Litestream::Commands.wal` method returns an array of hashes with the "replica", "generation", "index", "offset","size", and "created" keys for each wal:
424
+
425
+ ```ruby
426
+ Litestream::Commands.wal('storage/production.sqlite3')
427
+ # => [{"replica"=>"s3", "generation"=>"5f4341bc3d22d615", "index"=>"0", "offset"=>"0", "size"=>"2036", "created"=>"2024-04-17T19:48:09Z"}]
428
+ ```
429
+
430
+ You can also restore a database programmatically using the `Litestream::Commands.restore` method, which returns the path to the restored database:
273
431
 
274
432
  ```ruby
275
433
  Litestream::Commands.restore('storage/production.sqlite3')
@@ -104,6 +104,12 @@ module Litestream
104
104
  execute("snapshots", argv, database, async: async, tabled_output: true)
105
105
  end
106
106
 
107
+ def wal(database, async: false, **argv)
108
+ raise DatabaseRequiredException, "database argument is required for wal command, e.g. litestream:wal -- --database=path/to/database.sqlite" if database.nil?
109
+
110
+ execute("wal", argv, database, async: async, tabled_output: true)
111
+ end
112
+
107
113
  private
108
114
 
109
115
  def execute(command, argv = {}, database = nil, async: false, tabled_output: false)
@@ -1,3 +1,3 @@
1
1
  module Litestream
2
- VERSION = "0.11.2"
2
+ VERSION = "0.12.0"
3
3
  end
data/lib/litestream.rb CHANGED
@@ -19,7 +19,7 @@ module Litestream
19
19
 
20
20
  def self.configure
21
21
  deprecator.warn(
22
- 'Configuring Litestream via Litestream.configure is deprecated. Use Rails.application.configure { config.litestream.* = ... } instead.',
22
+ "Configuring Litestream via Litestream.configure is deprecated. Use Rails.application.configure { config.litestream.* = ... } instead.",
23
23
  caller
24
24
  )
25
25
  self.configuration ||= Configuration.new
@@ -33,7 +33,7 @@ module Litestream
33
33
  end
34
34
  end
35
35
 
36
- mattr_writer :username, :password, :queue, :replica_bucket, :replica_key_id, :replica_access_key
36
+ mattr_writer :username, :password, :queue, :replica_bucket, :replica_key_id, :replica_access_key, :systemctl_command
37
37
 
38
38
  class << self
39
39
  def verify!(database_path)
@@ -85,10 +85,14 @@ module Litestream
85
85
  @@replica_access_key || configuration.replica_access_key
86
86
  end
87
87
 
88
+ def systemctl_command
89
+ @@systemctl_command || "systemctl status litestream"
90
+ end
91
+
88
92
  def replicate_process
89
93
  info = {}
90
94
  if !`which systemctl`.empty?
91
- systemctl_status = `systemctl status litestream`.chomp
95
+ systemctl_status = `#{Litestream.systemctl_command}`.chomp
92
96
  # ["● litestream.service - Litestream",
93
97
  # " Loaded: loaded (/lib/systemd/system/litestream.service; enabled; vendor preset: enabled)",
94
98
  # " Active: active (running) since Tue 2023-07-25 13:49:43 UTC; 8 months 24 days ago",
@@ -115,7 +119,7 @@ module Litestream
115
119
  end
116
120
  end
117
121
  else
118
- litestream_replicate_ps = `ps -a | grep litestream | grep replicate`.chomp
122
+ litestream_replicate_ps = `ps -ax | grep litestream | grep replicate`.chomp
119
123
  litestream_replicate_ps.split("\n").each do |line|
120
124
  next unless line.include?("litestream replicate")
121
125
  pid, * = line.split(" ")
@@ -75,4 +75,18 @@ namespace :litestream do
75
75
 
76
76
  Litestream::Commands.snapshots(database, async: true, **options)
77
77
  end
78
+
79
+ desc "List all wal files for a database or replica, for example `rake litestream:wal -- -database=storage/production.sqlite3`"
80
+ task wal: :environment do
81
+ options = {}
82
+ if (separator_index = ARGV.index("--"))
83
+ ARGV.slice(separator_index + 1, ARGV.length)
84
+ .map { |pair| pair.split("=") }
85
+ .each { |opt| options[opt[0]] = opt[1] || nil }
86
+ end
87
+ database = options.delete("--database") || options.delete("-database")
88
+ options.symbolize_keys!
89
+
90
+ Litestream::Commands.wal(database, async: true, **options)
91
+ end
78
92
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: litestream
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.2
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Margheim
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-06 00:00:00.000000000 Z
11
+ date: 2024-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logfmt
@@ -203,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
203
  - !ruby/object:Gem::Version
204
204
  version: '0'
205
205
  requirements: []
206
- rubygems_version: 3.5.11
206
+ rubygems_version: 3.5.21
207
207
  signing_key:
208
208
  specification_version: 4
209
209
  summary: Integrate Litestream with the RubyGems infrastructure.