litestream 0.12.0-arm64-linux → 0.13.0-arm64-linux

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: 9216920fca85af36af4d39dc9d136ede430be9c07500e070ba76ead11f4bfa3d
4
- data.tar.gz: 974e031f0463ce100a4afdba55d0891191c1ca5235a04525f1d028e80330ac9d
3
+ metadata.gz: 876adbab4e47c730fa0b68e2cb8d500c1b1eaa9428fe781050f9710525b5f9a6
4
+ data.tar.gz: c387bf43c9aa47b4ee0c275adf2c75ecfc2fa81d6e765f40fe182f75535c4aca
5
5
  SHA512:
6
- metadata.gz: f8f1e4da34b5c99b4e5cf3e1342c30332ec3dc7251a19069014ef1d1b31131d9c6293603edac52ba20d971b1687adec643f037955365572b4cac12bb4dd1cc01
7
- data.tar.gz: 545769c8e2ca8dd7bc94492af4d9d418a21736098c58e2481639d7c72287af37eab6393c175254e39dd70b6ccab95c92eaed62d2f16b1fb7f6021ff9662ee57b
6
+ metadata.gz: 806a023befd6e62f2dd1cee59bdc54ca482a6a81a77212be7cbf58f48abb195287f17b0b6cb7e6cc305fd98cecd7bdb6a8d33cce2bcf23b0413d331abdd22ed4
7
+ data.tar.gz: 1fd1b2e5907b98b35b440bcba0b926ba03274a04bb41c669d300c694c1afac4373eef19f7362ce5f339b654981af9a6a4c86608ac632e859ba421b692db61ce2
data/README.md CHANGED
@@ -54,6 +54,7 @@ Supported platforms are:
54
54
 
55
55
  - arm64-darwin (macos-arm64)
56
56
  - x86_64-darwin (macos-x64)
57
+ - aarch64-linux (linux-aarch64)
57
58
  - arm64-linux (linux-arm64)
58
59
  - x86_64-linux (linux-x64)
59
60
 
@@ -92,7 +93,9 @@ dbs:
92
93
  secret-access-key: $LITESTREAM_SECRET_ACCESS_KEY
93
94
  ```
94
95
 
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:
96
+ This is the default for Amazon S3. The full range of possible replica types (e.g. other S3-compatible object storage servers) are covered in Litestream's [replica guides](https://litestream.io/guides/#replica-guides).
97
+
98
+ The gem also provides a default initializer file at `config/initializers/litestream.rb` that allows you to configure these three 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:
96
99
 
97
100
  ```ruby
98
101
  Rails.application.configure do
@@ -104,20 +107,19 @@ Rails.application.configure do
104
107
  end
105
108
  ```
106
109
 
107
- However, if you need manual control over the Litestream configuration, you can manually edit the `config/litestream.yml` file. The full range of possible configurations are covered in Litestream's [configuration reference](https://litestream.io/reference/config/).
110
+ However, if you need manual control over the Litestream configuration, you can manually edit the `config/litestream.yml` file. The full range of possible configurations are covered in Litestream's [configuration reference](https://litestream.io/reference/config/). NB: If you configure a longer `sync-interval`, you may need to adjust `replication_sleep` when calling `Litestream.verify!`.
108
111
 
109
112
  ### Replication
110
113
 
111
114
  In order to stream changes to your configured replicas, you need to start the Litestream replication process.
112
115
 
113
- The simplest way to run the Litestream replication process is use the Puma plugin provided by the gem. This allows you to run the Litestream replication process together with Puma and have Puma monitor and manage it. You just need to add
116
+ The simplest way to run the Litestream replication process is use the Puma plugin provided by the gem. This allows you to run the Litestream replication process together with Puma and have Puma monitor and manage it. You just need to add the following to your `puma.rb` configuration:
114
117
 
115
118
  ```ruby
116
- plugin :litestream
119
+ # Run litestream only in production.
120
+ plugin :litestream if ENV.fetch("RAILS_ENV", "production") == "production"
117
121
  ```
118
122
 
119
- to your `puma.rb` configuration.
120
-
121
123
  If you would prefer to run the Litestream replication process separately from Puma, you can use the provided `litestream:replicate` rake task. This rake task will automatically load the configuration file and set the environment variables before starting the Litestream process.
122
124
 
123
125
  The simplest way to spin up a Litestream process separately from your Rails application is to use a `Procfile`:
@@ -155,20 +157,32 @@ The Litestream `replicate` command supports the following options, which can be
155
157
 
156
158
  ### Restoration
157
159
 
158
- You can restore any replicated database at any point using the gem's provided `litestream:restore` rake task. This rake task requires that you specify which specific database you want to restore. As with the `litestream:replicate` task, you pass arguments to the rake task via argument forwarding. For example, to restore the production database, you would run:
160
+ You can restore any replicated database at any point using the gem's provided `litestream:restore` rake task. This rake task requires that you specify which specific database you want to restore. As with the `litestream:replicate` task, you pass arguments to the rake task via argument forwarding. For example, to restore the production database, you would do the following:
159
161
 
160
- ```shell
161
- bin/rails litestream:restore -- --database=storage/production.sqlite3
162
- # or
163
- bundle exec rake litestream:restore -- --database=storage/production.sqlite3
164
- ```
162
+ > [!NOTE]
163
+ > During the restoration process, you need to prevent any interaction with ActiveRecord/SQLite, such as from a running `rails server` or `rails console` instance. If there is any interaction, Rails might regenerate the production database and prevent restoration via litestream. If this happens, you might get a "cannot restore, output path already exists" error.
164
+
165
+ 1. Rename the production (`production.sqlite3`, `production.sqlite3-shm`, and `production.sqlite3-wal`) databases (**recommended**) or alternatively delete. To delete the production databases locally, you can run the following at your own risk:
166
+ ```shell
167
+ # DANGEROUS OPERATION, consider renaming database files instead
168
+ bin/rails db:drop DISABLE_DATABASE_ENVIRONMENT_CHECK=1
169
+ ```
170
+
171
+ 2. Run restore command:
172
+ ```shell
173
+ bin/rails litestream:restore -- --database=storage/production.sqlite3
174
+ # or
175
+ bundle exec rake litestream:restore -- --database=storage/production.sqlite3
176
+ ```
177
+
178
+ 3. Restart your Rails application or Docker container if applicable.
165
179
 
166
180
  You can restore any of the databases specified in your `config/litestream.yml` file. The `--database` argument should be the path to the database file you want to restore and must match the value for the `path` key of one of your configured databases. The `litestream:restore` rake task will automatically load the configuration file and set the environment variables before calling the Litestream executable.
167
181
 
168
182
  If you need to pass arguments through the rake task to the underlying `litestream` command, that can be done with additional forwarded arguments:
169
183
 
170
184
  ```shell
171
- bin/rails litestream:replicate -- --database=storage/production.sqlite3 --if-db-not-exists
185
+ bin/rails litestream:restore -- --database=storage/production.sqlite3 --if-db-not-exists
172
186
  ```
173
187
 
174
188
  You can forward arguments in whatever order you like, you simply need to ensure that the `--database` argument is present. You can also use either a single-dash `-database` or double-dash `--database` argument format. The Litestream `restore` command supports the following options, which can be passed through the rake task:
@@ -220,7 +234,7 @@ You can verify the integrity of your backed-up databases using the gem's provide
220
234
  Litestream.verify! "storage/production.sqlite3"
221
235
  ```
222
236
 
223
- In order to verify that the backup for that database is both restorable and fresh, the method will add a new row to that database under the `_litestream_verification` table, which it will create if needed. It will then wait 10 seconds to give the Litestream utility time to replicate that change to whatever storage providers you have configured. After that, it will download the latest backup from that storage provider and ensure that this verification row is present in the backup. If the verification row is _not_ present, the method will raise a `Litestream::VerificationFailure` exception. This check ensures that the restored database file
237
+ In order to verify that the backup for that database is both restorable and fresh, the method will add a new row to that database under the `_litestream_verification` table, which it will create if needed. It will then wait `replication_sleep` seconds (defaults to 10) to give the Litestream utility time to replicate that change to whatever storage providers you have configured. After that, it will download the latest backup from that storage provider and ensure that this verification row is present in the backup. If the verification row is _not_ present, the method will raise a `Litestream::VerificationFailure` exception. This check ensures that the restored database file:
224
238
 
225
239
  1. exists,
226
240
  2. can be opened by SQLite, and
@@ -256,8 +270,8 @@ Second, you can configure the access credentials via the Rails configuration obj
256
270
 
257
271
  ```ruby
258
272
  # Set authentication credentials for Litestream
259
- config.litestream.username = Rails.application.credentials.litestream.username
260
- config.litestream.password = Rails.application.credentials.litestream.password
273
+ config.litestream.username = Rails.application.credentials.dig(:litestream, :username)
274
+ config.litestream.password = Rails.application.credentials.dig(:litestream, :password)
261
275
  ```
262
276
 
263
277
  Either way, if you have set a username and password, Litestream will use basic HTTP authentication.
@@ -269,7 +283,7 @@ If you use Devise for authentication in your app, you can also restrict access t
269
283
 
270
284
  ```ruby
271
285
  authenticate :user, -> (user) { user.admin? } do
272
- mount LitestreamRails::Engine, at: "/litestream"
286
+ mount Litestream::Engine, at: "/litestream"
273
287
  end
274
288
  ```
275
289
 
@@ -294,7 +308,7 @@ config.middleware.use ActionDispatch::Flash
294
308
 
295
309
  ### Overwriting the views
296
310
 
297
- You can find the views in [`app/views`](https://github.com/fractaledmind/litestream/tree/main/app/views).
311
+ You can find the views in [`app/views`](https://github.com/fractaledmind/litestream-ruby/tree/main/app/views).
298
312
 
299
313
  ```bash
300
314
  app/views/
@@ -362,7 +376,7 @@ You can also list the generations of a specific database:
362
376
  bin/rails litestream:generations -- --database=storage/production.sqlite3
363
377
  ```
364
378
 
365
- This will list all generations for the specified database, including stats about their lag behind the primary database and the time range they cover.
379
+ This will list all generations for the specified database, including stats about their lag behind the primary database and the time range they cover:
366
380
 
367
381
  ```
368
382
  name generation lag start end
@@ -434,13 +448,6 @@ Litestream::Commands.restore('storage/production.sqlite3')
434
448
  # => "storage/production-20240418090048.sqlite3"
435
449
  ```
436
450
 
437
- Finally, you can verify the integrity of a restored database using the `Litestream::Commands.verify` method, which returns a hash with the "size" and "tables" keys for the original and restored databases:
438
-
439
- ```ruby
440
- Litestream::Commands.verify('storage/production.sqlite3')
441
- # => {"size"=>{"original"=>21688320, "restored"=>21688320}, "tables"=>{"original"=>9, "restored"=>9}}
442
- ```
443
-
444
451
  You _can_ start the replication process using the `Litestream::Commands.replicate` method, but this is not recommended. The replication process should be managed by Litestream itself, and you should not need to manually start it.
445
452
 
446
453
  ### Running commands from CLI
@@ -461,7 +468,13 @@ litestream wal [arguments] DB_PATH|REPLICA_URL
461
468
 
462
469
  ### Using in development
463
470
 
464
- By default, installing the gem does not update your `Procfile.dev` file, and so Litestream will not be started in development. If you would like to test that your configuration is properly setup, you can manually add the `litestream:replicate` rake task to your `Procfile.dev` file. Just copy the `litestream` definition from the production `Procfile`. Then, in order to have a replication bucket for Litestream to point to, you can use a Docker instance of [MinIO](https://min.io/). MinIO is an S3-compatible object storage server that can be run locally. You can run a MinIO server with the following command:
471
+ By default, if you install the gem and configure via `puma.rb` or `Procfile`, Litestream will not start in development.
472
+
473
+ If you setup via `puma.rb`, then remove the conditional statement.
474
+
475
+ If you setup via `Procfile`, you will need to update your `Procfile.dev` file. If you would like to test that your configuration is properly setup, you can manually add the `litestream:replicate` rake task to your `Procfile.dev` file. Just copy the `litestream` definition from the production `Procfile`.
476
+
477
+ In order to have a replication bucket for Litestream to point to, you can use a Docker instance of [MinIO](https://min.io/). MinIO is an S3-compatible object storage server that can be run locally. You can run a MinIO server with the following command:
465
478
 
466
479
  ```sh
467
480
  docker run -p 9000:9000 -p 9001:9001 minio/minio server /data --console-address ":9001"
@@ -1,7 +1,6 @@
1
1
  module Litestream
2
- class ApplicationController < ActionController::Base
2
+ class ApplicationController < Litestream.base_controller_class.constantize
3
3
  protect_from_forgery with: :exception
4
- around_action :force_english_locale!
5
4
 
6
5
  if Litestream.password
7
6
  http_basic_authenticate_with(
@@ -9,11 +8,5 @@ module Litestream
9
8
  password: Litestream.password
10
9
  )
11
10
  end
12
-
13
- private
14
-
15
- def force_english_locale!(&action)
16
- I18n.with_locale(:en, &action)
17
- end
18
11
  end
19
12
  end
@@ -801,4 +801,42 @@
801
801
  .hover\:underline:hover {
802
802
  text-decoration-line: underline;
803
803
  }
804
+ @media (prefers-color-scheme: dark) {
805
+ .dark\:border-gray-800 {
806
+ --tw-border-opacity: 1;
807
+ border-color: rgb(31 41 55 / var(--tw-border-opacity));
808
+ }
809
+ .dark\:bg-gray-900 {
810
+ --tw-bg-opacity: 1;
811
+ background-color: rgb(17 24 39 / var(--tw-bg-opacity));
812
+ }
813
+ .dark\:bg-green-900 {
814
+ --tw-bg-opacity: 1;
815
+ background-color: rgb(20 83 45 / var(--tw-bg-opacity));
816
+ }
817
+ .dark\:bg-red-900 {
818
+ --tw-bg-opacity: 1;
819
+ background-color: rgb(127 29 29 / var(--tw-bg-opacity));
820
+ }
821
+ .dark\:text-gray-100 {
822
+ --tw-text-opacity: 1;
823
+ color: rgb(243 244 246 / var(--tw-text-opacity));
824
+ }
825
+ .dark\:text-white {
826
+ --tw-text-opacity: 1;
827
+ color: rgb(255 255 255 / var(--tw-text-opacity));
828
+ }
829
+ .dark\:even\:bg-gray-800:nth-child(even) {
830
+ --tw-bg-opacity: 1;
831
+ background-color: rgb(31 41 55 / var(--tw-bg-opacity));
832
+ }
833
+ .dark\:hover\:bg-gray-900:hover {
834
+ --tw-bg-opacity: 1;
835
+ background-color: rgb(17 24 39 / var(--tw-bg-opacity));
836
+ }
837
+ .dark\:hover\:bg-gray-800:hover {
838
+ --tw-bg-opacity: 1;
839
+ background-color: rgb(31 41 55 / var(--tw-bg-opacity));
840
+ }
841
+ }
804
842
  </style>
@@ -7,22 +7,22 @@
7
7
 
8
8
  <%= render "layouts/litestream/style" %>
9
9
  </head>
10
- <body class="h-full flex flex-col">
10
+ <body class="h-full flex flex-col dark:bg-gray-900 dark:text-white">
11
11
  <main class="container mx-auto max-w-4xl mt-4 px-2 grow">
12
12
  <%= content_for?(:content) ? yield(:content) : yield %>
13
13
  </main>
14
14
 
15
- <footer class="container mx-auto mt-24 flex items-center justify-between border-t px-2 py-4 text-base">
15
+ <footer class="container mx-auto mt-24 flex items-center justify-between border-t dark:border-gray-800 px-2 py-4 text-base">
16
16
  <p>
17
17
  <code><strong>Litestream</strong></code>&nbsp;&nbsp;|&nbsp;
18
- Made by <a href="https://twitter.com/fractaledmind" class="text-blue-500 hover:underline decoration-blue-500">@fractaledmind</a> and <a href="https://github.com/fractaledmind/litestream/graphs/contributors" class="text-blue-500 hover:underline decoration-blue-500">friends</a>! Want to help? It's <a href="https://github.com/fractaledmind/litestream" class="text-blue-500 hover:underline decoration-blue-500">open source</a>!
18
+ Made by <a href="https://twitter.com/fractaledmind" class="text-blue-500 hover:underline decoration-blue-500">@fractaledmind</a> and <a href="https://github.com/fractaledmind/litestream-ruby/graphs/contributors" class="text-blue-500 hover:underline decoration-blue-500">friends</a>! Want to help? It's <a href="https://github.com/fractaledmind/litestream-ruby" class="text-blue-500 hover:underline decoration-blue-500">open source</a>!
19
19
  </p>
20
20
  </footer>
21
21
 
22
22
  <div class="fixed top-0 left-0 right-0 text-center py-2">
23
23
  <% if notice.present? %>
24
24
  <p id="notice"
25
- class="py-2 px-3 bg-green-50 text-green-500 font-medium rounded-lg inline-block"
25
+ class="py-2 px-3 bg-green-50 dark:bg-green-900 text-green-500 font-medium rounded-lg inline-block"
26
26
  data-controller="fade">
27
27
  <%= notice.html_safe %>
28
28
  </p>
@@ -30,7 +30,7 @@
30
30
 
31
31
  <% if alert.present? %>
32
32
  <p id="alert"
33
- class="py-2 px-3 bg-red-50 text-red-500 font-medium rounded-lg inline-block"
33
+ class="py-2 px-3 bg-red-50 dark:bg-red-900 text-red-500 font-medium rounded-lg inline-block"
34
34
  data-controller="fade">
35
35
  <%= alert.html_safe %>
36
36
  </p>
@@ -40,7 +40,7 @@
40
40
  <br>
41
41
 
42
42
  <section id="databases" class="">
43
- <div class="mb-3 flex items-center justify-between border-b">
43
+ <div class="mb-3 flex items-center justify-between border-b dark:border-gray-800">
44
44
  <h2 class="text-2xl font-bold">Databases</h2>
45
45
  <p class="text-right">Total: <strong><%= @databases.size %></strong></p>
46
46
  </div>
@@ -59,7 +59,7 @@
59
59
  <section id="generations" class="ml-6">
60
60
  <% database['generations'].each do |generation| %>
61
61
  <details id="<%= generation['generation'] %>" open="open">
62
- <summary class="cursor-pointer rounded p-2 hover:bg-gray-50">
62
+ <summary class="cursor-pointer rounded p-2 hover:bg-gray-50 dark:hover:bg-gray-800">
63
63
  <code><%= generation['generation'] %></code>
64
64
  (<em><%= generation['lag'] %> lag</em>)
65
65
  </summary>
@@ -85,24 +85,24 @@
85
85
  <table class="min-w-full divide-y divide-gray-300">
86
86
  <thead>
87
87
  <tr>
88
- <th scope="col" class="whitespace-nowrap px-2 py-2 text-left text-sm font-semibold text-gray-900">Created at</th>
89
- <th scope="col" class="whitespace-nowrap px-2 py-2 text-right text-sm font-semibold text-gray-900">Index</th>
90
- <th scope="col" class="whitespace-nowrap px-2 py-2 text-right text-sm font-semibold text-gray-900">Size</th>
88
+ <th scope="col" class="whitespace-nowrap px-2 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">Created at</th>
89
+ <th scope="col" class="whitespace-nowrap px-2 py-2 text-right text-sm font-semibold text-gray-900 dark:text-gray-100">Index</th>
90
+ <th scope="col" class="whitespace-nowrap px-2 py-2 text-right text-sm font-semibold text-gray-900 dark:text-gray-100">Size</th>
91
91
  </tr>
92
92
  </thead>
93
93
 
94
- <tbody class="bg-white">
94
+ <tbody class="bg-white dark:bg-gray-900">
95
95
  <% generation['snapshots'].each do |snapshot| %>
96
- <tr class="align-top even:bg-gray-50">
97
- <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900">
96
+ <tr class="align-top even:bg-gray-50 dark:even:bg-gray-800">
97
+ <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100">
98
98
  <abbr title="<%= snapshot['created'] %>" class="underline decoration-dashed decoration-gray-500 cursor-help">
99
99
  <time datetime="<%= snapshot['created'] %>"><%= DateTime.parse(snapshot['created']).to_formatted_s(:db) %></time>
100
100
  </abbr>
101
101
  </td>
102
- <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 text-right">
102
+ <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100 text-right">
103
103
  <%= snapshot['index'] %>
104
104
  </td>
105
- <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 text-right">
105
+ <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100 text-right">
106
106
  <%= number_to_human_size snapshot['size'] %>
107
107
  </td>
108
108
  </tr>
@@ -125,11 +125,13 @@ module Litestream
125
125
 
126
126
  def prepare(command, argv = {}, database = nil)
127
127
  ENV["LITESTREAM_REPLICA_BUCKET"] ||= Litestream.replica_bucket
128
+ ENV["LITESTREAM_REPLICA_REGION"] ||= Litestream.replica_region
129
+ ENV["LITESTREAM_REPLICA_ENDPOINT"] ||= Litestream.replica_endpoint
128
130
  ENV["LITESTREAM_ACCESS_KEY_ID"] ||= Litestream.replica_key_id
129
131
  ENV["LITESTREAM_SECRET_ACCESS_KEY"] ||= Litestream.replica_access_key
130
132
 
131
133
  args = {
132
- "--config" => Rails.root.join("config", "litestream.yml").to_s
134
+ "--config" => Litestream.config_path.to_s
133
135
  }.merge(argv.stringify_keys).to_a.flatten.compact
134
136
  cmd = [executable, command, *args, database].compact
135
137
  puts cmd.inspect if ENV["DEBUG"]
@@ -2,7 +2,7 @@
2
2
  # All configuration options will be available as environment variables, e.g.
3
3
  # config.replica_bucket becomes LITESTREAM_REPLICA_BUCKET
4
4
  # This allows you to configure Litestream using Rails encrypted credentials,
5
- # or some other mechanism where the values are only avaialble at runtime.
5
+ # or some other mechanism where the values are only available at runtime.
6
6
 
7
7
  Rails.application.configure do
8
8
  # An example of using Rails encrypted credentials to configure Litestream.
@@ -4,6 +4,7 @@ module Litestream
4
4
 
5
5
  # rubygems platform name => upstream release filename
6
6
  NATIVE_PLATFORMS = {
7
+ "aarch64-linux" => "litestream-#{VERSION}-linux-arm64.tar.gz",
7
8
  "arm64-darwin" => "litestream-#{VERSION}-darwin-arm64.zip",
8
9
  "arm64-linux" => "litestream-#{VERSION}-linux-arm64.tar.gz",
9
10
  "x86_64-darwin" => "litestream-#{VERSION}-darwin-amd64.zip",
@@ -1,3 +1,3 @@
1
1
  module Litestream
2
- VERSION = "0.12.0"
2
+ VERSION = "0.13.0"
3
3
  end
data/lib/litestream.rb CHANGED
@@ -33,16 +33,18 @@ module Litestream
33
33
  end
34
34
  end
35
35
 
36
- mattr_writer :username, :password, :queue, :replica_bucket, :replica_key_id, :replica_access_key, :systemctl_command
36
+ mattr_writer :username, :password, :queue, :replica_bucket, :replica_region, :replica_endpoint, :replica_key_id, :replica_access_key, :systemctl_command,
37
+ :config_path
38
+ mattr_accessor :base_controller_class, default: "::ApplicationController"
37
39
 
38
40
  class << self
39
- def verify!(database_path)
41
+ def verify!(database_path, replication_sleep: 10)
40
42
  database = SQLite3::Database.new(database_path)
41
43
  database.execute("CREATE TABLE IF NOT EXISTS _litestream_verification (id INTEGER PRIMARY KEY, uuid BLOB)")
42
44
  sentinel = SecureRandom.uuid
43
45
  database.execute("INSERT INTO _litestream_verification (uuid) VALUES (?)", [sentinel])
44
46
  # give the Litestream replication process time to replicate the sentinel value
45
- sleep 10
47
+ sleep replication_sleep
46
48
 
47
49
  backup_path = "tmp/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_#{sentinel}.sqlite3"
48
50
  Litestream::Commands.restore(database_path, **{"-o" => backup_path})
@@ -77,6 +79,14 @@ module Litestream
77
79
  @@replica_bucket || configuration.replica_bucket
78
80
  end
79
81
 
82
+ def replica_region
83
+ @@replica_region
84
+ end
85
+
86
+ def replica_endpoint
87
+ @@replica_endpoint
88
+ end
89
+
80
90
  def replica_key_id
81
91
  @@replica_key_id || configuration.replica_key_id
82
92
  end
@@ -89,55 +99,12 @@ module Litestream
89
99
  @@systemctl_command || "systemctl status litestream"
90
100
  end
91
101
 
102
+ def config_path
103
+ @@config_path || Rails.root.join("config", "litestream.yml")
104
+ end
105
+
92
106
  def replicate_process
93
- info = {}
94
- if !`which systemctl`.empty?
95
- systemctl_status = `#{Litestream.systemctl_command}`.chomp
96
- # ["● litestream.service - Litestream",
97
- # " Loaded: loaded (/lib/systemd/system/litestream.service; enabled; vendor preset: enabled)",
98
- # " Active: active (running) since Tue 2023-07-25 13:49:43 UTC; 8 months 24 days ago",
99
- # " Main PID: 1179656 (litestream)",
100
- # " Tasks: 9 (limit: 1115)",
101
- # " Memory: 22.9M",
102
- # " CPU: 10h 49.843s",
103
- # " CGroup: /system.slice/litestream.service",
104
- # " └─1179656 /usr/bin/litestream replicate",
105
- # "",
106
- # "Warning: some journal files were not opened due to insufficient permissions."]
107
- systemctl_status.split("\n").each do |line|
108
- line.strip!
109
- if line.start_with?("Main PID:")
110
- _key, value = line.split(":")
111
- pid, _name = value.strip.split(" ")
112
- info[:pid] = pid
113
- elsif line.start_with?("Active:")
114
- value, _ago = line.split(";")
115
- status, timestamp = value.split(" since ")
116
- info[:started] = DateTime.strptime(timestamp.strip, "%a %Y-%m-%d %H:%M:%S %Z")
117
- status_match = status.match(%r{\((?<status>.*)\)})
118
- info[:status] = status_match ? status_match[:status] : nil
119
- end
120
- end
121
- else
122
- litestream_replicate_ps = `ps -ax | grep litestream | grep replicate`.chomp
123
- litestream_replicate_ps.split("\n").each do |line|
124
- next unless line.include?("litestream replicate")
125
- pid, * = line.split(" ")
126
- info[:pid] = pid
127
- state, _, lstart = `ps -o "state,lstart" #{pid}`.chomp.split("\n").last.partition(/\s+/)
128
-
129
- info[:status] = case state[0]
130
- when "I" then "idle"
131
- when "R" then "running"
132
- when "S" then "sleeping"
133
- when "T" then "stopped"
134
- when "U" then "uninterruptible"
135
- when "Z" then "zombie"
136
- end
137
- info[:started] = DateTime.strptime(lstart.strip, "%a %b %d %H:%M:%S %Y")
138
- end
139
- end
140
- info
107
+ systemctl_info || process_info || {}
141
108
  end
142
109
 
143
110
  def databases
@@ -157,6 +124,71 @@ module Litestream
157
124
  end
158
125
  end
159
126
  end
127
+
128
+ private
129
+
130
+ def systemctl_info
131
+ return if `which systemctl`.empty?
132
+
133
+ systemctl_output = `#{Litestream.systemctl_command}`
134
+ systemctl_exit_code = $?.exitstatus
135
+ return unless systemctl_exit_code.zero?
136
+
137
+ # ["● litestream.service - Litestream",
138
+ # " Loaded: loaded (/lib/systemd/system/litestream.service; enabled; vendor preset: enabled)",
139
+ # " Active: active (running) since Tue 2023-07-25 13:49:43 UTC; 8 months 24 days ago",
140
+ # " Main PID: 1179656 (litestream)",
141
+ # " Tasks: 9 (limit: 1115)",
142
+ # " Memory: 22.9M",
143
+ # " CPU: 10h 49.843s",
144
+ # " CGroup: /system.slice/litestream.service",
145
+ # " └─1179656 /usr/bin/litestream replicate",
146
+ # "",
147
+ # "Warning: some journal files were not opened due to insufficient permissions."]
148
+
149
+ info = {}
150
+ systemctl_output.chomp.split("\n").each do |line|
151
+ line.strip!
152
+ if line.start_with?("Main PID:")
153
+ _key, value = line.split(":")
154
+ pid, _name = value.strip.split(" ")
155
+ info[:pid] = pid
156
+ elsif line.start_with?("Active:")
157
+ value, _ago = line.split(";")
158
+ status, timestamp = value.split(" since ")
159
+ info[:started] = DateTime.strptime(timestamp.strip, "%a %Y-%m-%d %H:%M:%S %Z")
160
+ status_match = status.match(%r{\((?<status>.*)\)})
161
+ info[:status] = status_match ? status_match[:status] : nil
162
+ end
163
+ end
164
+ info
165
+ end
166
+
167
+ def process_info
168
+ litestream_replicate_ps = `ps -ax | grep litestream | grep replicate`
169
+ exit_code = $?.exitstatus
170
+ return unless exit_code.zero?
171
+
172
+ info = {}
173
+ litestream_replicate_ps.chomp.split("\n").each do |line|
174
+ next unless line.include?("litestream replicate")
175
+
176
+ pid, * = line.split(" ")
177
+ info[:pid] = pid
178
+ state, _, lstart = `ps -o "state,lstart" #{pid}`.chomp.split("\n").last.partition(/\s+/)
179
+
180
+ info[:status] = case state[0]
181
+ when "I" then "idle"
182
+ when "R" then "running"
183
+ when "S" then "sleeping"
184
+ when "T" then "stopped"
185
+ when "U" then "uninterruptible"
186
+ when "Z" then "zombie"
187
+ end
188
+ info[:started] = DateTime.strptime(lstart.strip, "%a %b %d %H:%M:%S %Y")
189
+ end
190
+ info
191
+ end
160
192
  end
161
193
  end
162
194
 
@@ -2,6 +2,8 @@ namespace :litestream do
2
2
  desc "Print the ENV variables needed for the Litestream config file"
3
3
  task env: :environment do
4
4
  puts "LITESTREAM_REPLICA_BUCKET=#{Litestream.replica_bucket}"
5
+ puts "LITESTREAM_REPLICA_REGION=#{Litestream.replica_region}"
6
+ puts "LITESTREAM_REPLICA_ENDPOINT=#{Litestream.replica_endpoint}"
5
7
  puts "LITESTREAM_ACCESS_KEY_ID=#{Litestream.replica_key_id}"
6
8
  puts "LITESTREAM_SECRET_ACCESS_KEY=#{Litestream.replica_access_key}"
7
9
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: litestream
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: arm64-linux
6
6
  authors:
7
7
  - Stephen Margheim
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-10-22 00:00:00.000000000 Z
10
+ date: 2025-06-03 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: logfmt
@@ -150,7 +149,6 @@ dependencies:
150
149
  - - ">="
151
150
  - !ruby/object:Gem::Version
152
151
  version: '0'
153
- description:
154
152
  email:
155
153
  - stephen.margheim@gmail.com
156
154
  executables:
@@ -190,7 +188,6 @@ metadata:
190
188
  rubygems_mfa_required: 'true'
191
189
  source_code_uri: https://github.com/fractaledmind/litestream-ruby
192
190
  changelog_uri: https://github.com/fractaledmind/litestream-ruby/CHANGELOG.md
193
- post_install_message:
194
191
  rdoc_options: []
195
192
  require_paths:
196
193
  - lib
@@ -205,8 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
202
  - !ruby/object:Gem::Version
206
203
  version: '0'
207
204
  requirements: []
208
- rubygems_version: 3.5.21
209
- signing_key:
205
+ rubygems_version: 3.6.3
210
206
  specification_version: 4
211
207
  summary: Integrate Litestream with the RubyGems infrastructure.
212
208
  test_files: []