Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions .github/workflows/gem-install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,6 @@ jobs:
# litestream version
# "

darwin-x86_64-install:
needs: ["package"]
runs-on: macos-13
steps:
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2"
- uses: actions/download-artifact@v4
with:
name: gem-x86_64-darwin
path: pkg
- run: "gem install pkg/litestream-*.gem"
- run: "litestream version"

darwin-arm64-install:
needs: ["package"]
runs-on: macos-14
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
## [Unreleased]

## [0.15.0] - 2026-02-25

### Major Changes

- **Bump to Litestream 0.5.9**: Replaced `wal` command with `ltx` command (Litestream 0.5.x changed WAL terminology to LTX)
- **Updated configuration format**: Config template now uses Litestream's new `globals` and `unique replica` format
- **New IPC-based dashboard**: Dashboard now uses Litestream's native IPC socket (`/info` and `/list` endpoints) instead of parsing CLI output

### Deprecations

- **Removed `generations` command**: Deprecated in Litestream 0.5.x, now removed
- **Removed `snapshots` command**: Deprecated in Litestream 0.5.x, now removed

## [0.14.0] - 2025-06-14

- Change async behaviour of replicate and other commands ([@hschne](https://github.com/fractaledmind/litestream-ruby/pull/62))
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
litestream (0.14.0)
litestream (0.15.0)
actionpack (>= 7.0)
actionview (>= 7.0)
activejob (>= 7.0)
Expand Down
72 changes: 18 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

[Litestream](https://litestream.io/) is a standalone streaming replication tool for SQLite. This gem provides a Ruby interface to Litestream.

> [!WARNING]
> This is the README for versions >= 0.15 which uses [Litestream 0.5.x](https://litestream.io), it introduces breaking changes because of how the Litestream now handles its replicate process. If you use an older version please read the [Litestream migration guide](https://litestream.io/docs/migration/). **TL;DR** you have to update your `config/litestream.yml` file, and `generations` / `snapshots` are replaced with `ltx` so the corresponding commands are no longer available.

## Installation

Install the gem and add to the application's Gemfile by executing:
Expand Down Expand Up @@ -85,14 +88,17 @@ The gem streamlines the configuration process by providing a default configurati
The default configuration file looks like this if you only have one SQLite database:

```yaml
access-key-id: $LITESTREAM_ACCESS_KEY_ID
secret-access-key: $LITESTREAM_SECRET_ACCESS_KEY
region: $LITESTREAM_REGION
endpoint: $LITESTREAM_ENDPOINT

dbs:
- path: storage/production.sqlite3
replicas:
- type: s3
path: storage/production.sqlite3
bucket: $LITESTREAM_REPLICA_BUCKET
access-key-id: $LITESTREAM_ACCESS_KEY_ID
secret-access-key: $LITESTREAM_SECRET_ACCESS_KEY
replica:
type: s3
path: storage/production.sqlite3
bucket: $LITESTREAM_REPLICA_BUCKET
```

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).
Expand Down Expand Up @@ -391,39 +397,13 @@ path replicas
/Users/you/Code/your-app/storage/production.sqlite3 s3
```

You can also list the generations of a specific database:

```shell
bin/rails litestream:generations -- --database=storage/production.sqlite3
```

This will list all generations for the specified database, including stats about their lag behind the primary database and the time range they cover:

```
name generation lag start end
s3 a295b16a796689f3 -156ms 2024-04-17T00:01:19Z 2024-04-17T00:01:19Z
```

You can list the snapshots available for a database:

```shell
bin/rails litestream:snapshots -- --database=storage/production.sqlite3
```

This command lists snapshots available for that specified database:

```
replica generation index size created
s3 a295b16a796689f3 1 4645465 2024-04-17T00:01:19Z
```

Finally, you can list the wal files available for a database:
Finally, you can list the ltx files available for a database:

```shell
bin/rails litestream:wal -- --database=storage/production.sqlite3
bin/rails litestream:ltx -- --database=storage/production.sqlite3
```

This command lists wal files available for that specified database:
This command lists ltx files available for that specified database:

```
replica generation index offset size created
Expand All @@ -441,24 +421,10 @@ Litestream::Commands.databases
# => [{"path"=>"/Users/you/Code/your-app/storage/production.sqlite3", "replicas"=>"s3"}]
```

The `Litestream::Commands.generations` method returns an array of hashes with the "name", "generation", "lag", "start", and "end" keys for each generation:

```ruby
Litestream::Commands.generations('storage/production.sqlite3')
# => [{"name"=>"s3", "generation"=>"5f4341bc3d22d615", "lag"=>"3s", "start"=>"2024-04-17T19:48:09Z", "end"=>"2024-04-17T19:48:09Z"}]
```

The `Litestream::Commands.snapshots` method returns an array of hashes with the "replica", "generation", "index", "size", and "created" keys for each snapshot:

```ruby
Litestream::Commands.snapshots('storage/production.sqlite3')
# => [{"replica"=>"s3", "generation"=>"5f4341bc3d22d615", "index"=>"0", "size"=>"4645465", "created"=>"2024-04-17T19:48:09Z"}]
```

The `Litestream::Commands.wal` method returns an array of hashes with the "replica", "generation", "index", "offset","size", and "created" keys for each wal:
The `Litestream::Commands.ltx` method returns an array of hashes with the "replica", "generation", "index", "offset","size", and "created" keys for each ltx:

```ruby
Litestream::Commands.wal('storage/production.sqlite3')
Litestream::Commands.ltx('storage/production.sqlite3')
# => [{"replica"=>"s3", "generation"=>"5f4341bc3d22d615", "index"=>"0", "offset"=>"0", "size"=>"2036", "created"=>"2024-04-17T19:48:09Z"}]
```

Expand All @@ -479,12 +445,10 @@ The full set of commands available to the `litestream` executable are covered in

```shell
litestream databases [arguments]
litestream generations [arguments] DB_PATH|REPLICA_URL
litestream replicate [arguments]
litestream restore [arguments] DB_PATH|REPLICA_URL
litestream snapshots [arguments] DB_PATH|REPLICA_URL
litestream version
litestream wal [arguments] DB_PATH|REPLICA_URL
litestream ltx [arguments] DB_PATH|REPLICA_URL
```

### Using in development
Expand Down
115 changes: 61 additions & 54 deletions app/views/litestream/processes/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -55,65 +55,72 @@
<%= button_to "Restore", restorations_path, class: "rounded-md bg-slate-800 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-slate-700", params: { database: database['path'] } %>
</div>

<br />
<section id="generations" class="ml-6">
<% database['generations'].each do |generation| %>
<details id="<%= generation['generation'] %>" open="open">
<summary class="cursor-pointer rounded p-2 hover:bg-gray-50 dark:hover:bg-gray-800">
<code><%= generation['generation'] %></code>
(<em><%= generation['lag'] %> lag</em>)
</summary>
<dl class="ml-4 grid grid-cols-[fit-content(100%)_1fr] gap-x-4">
<dt class="font-bold">Status</dt>
<dd class=""><%= database['status'] %></dd>

<dl class="ml-7 grid grid-cols-[fit-content(100%)_1fr] gap-x-4">
<dt class="font-bold">Start</dt>
<dd class="">
<abbr title="<%= generation['start'] %>" class="underline decoration-dashed decoration-gray-500 cursor-help">
<time datetime="<%= generation['start'] %>"><%= DateTime.parse(generation['start']).to_formatted_s(:db) %></time>
</abbr>
</dd>
<dt class="font-bold">Last sync</dt>
<dd class="">
<% if database['last_sync_at'] %>
<abbr title="<%= database['last_sync_at'] %>" class="underline decoration-dashed decoration-gray-500 cursor-help">
<time datetime="<%= database['last_sync_at'] %>"><%= DateTime.parse(database['last_sync_at']).to_formatted_s(:db) %></time>
</abbr>
<% else %>
Never
<% end %>
</dd>
</dl>

<br />
<section id="ltx" class="ml-6">
<details open="open">
<summary class="cursor-pointer rounded p-2 hover:bg-gray-50 dark:hover:bg-gray-800">
LTX Files (<em><%= Array(database['ltx']).size %> files</em>)
</summary>

<dt class="font-bold">End</dt>
<dl class="ml-7 grid grid-cols-[fit-content(100%)_1fr] gap-x-4">
<div class="col-span-2">
<dt class="font-bold">LTX Files</dt>
<dd class="">
<abbr title="<%= generation['end'] %>" class="underline decoration-dashed decoration-gray-500 cursor-help">
<time datetime="<%= generation['end'] %>"><%= DateTime.parse(generation['end']).to_formatted_s(:db) %></time>
</abbr>
</dd>
<table class="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th scope="col" class="whitespace-nowrap px-2 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">Level</th>
<th scope="col" class="whitespace-nowrap px-2 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">Min TXID</th>
<th scope="col" class="whitespace-nowrap px-2 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">Max TXID</th>
<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>
<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>
</tr>
</thead>

<div class="col-span-2">
<dt class="font-bold">Snapshots</dt>
<dd class="">
<table class="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<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>
<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>
<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>
<tbody class="bg-white dark:bg-gray-900">
<% database['ltx'].each do |ltx| %>
<tr class="align-top even:bg-gray-50 dark:even:bg-gray-800">
<td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100">
<%= ltx['level'] %>
</td>
<td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100">
<%= ltx['min_txid'] %>
</td>
<td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100">
<%= ltx['max_txid'] %>
</td>
<td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100">
<abbr title="<%= ltx['created'] %>" class="underline decoration-dashed decoration-gray-500 cursor-help">
<time datetime="<%= ltx['created'] %>"><%= DateTime.parse(ltx['created']).to_formatted_s(:db) %></time>
</abbr>
</td>
<td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100 text-right">
<%= number_to_human_size ltx['size'] %>
</td>
</tr>
</thead>

<tbody class="bg-white dark:bg-gray-900">
<% generation['snapshots'].each do |snapshot| %>
<tr class="align-top even:bg-gray-50 dark:even:bg-gray-800">
<td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100">
<abbr title="<%= snapshot['created'] %>" class="underline decoration-dashed decoration-gray-500 cursor-help">
<time datetime="<%= snapshot['created'] %>"><%= DateTime.parse(snapshot['created']).to_formatted_s(:db) %></time>
</abbr>
</td>
<td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100 text-right">
<%= snapshot['index'] %>
</td>
<td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100 text-right">
<%= number_to_human_size snapshot['size'] %>
</td>
</tr>
<% end %>
</tbody>
</table>
</dd>
</div>
</dl>
</details>
<% end %>
<% end %>
</tbody>
</table>
</dd>
</div>
</dl>
</details>
</section>
</li>
<% end %>
Expand Down
Binary file modified images/show-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading