mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 01:15:03 +03:00
feat(studio): show table WAL retention headroom (#50499)
## What kind of change does this PR introduce? Feature ## What is the current behavior? Replicated table rows show their temporary sync slot's pending bytes, WAL risk, and last check-in, but omit the amount of WAL retention remaining. ## What is the new behavior? Replicated table rows include the temporary slot's WAL retention headroom alongside the existing sync details. Finite values use a compact byte value, an explicit unlimited value is labelled `Unlimited WAL retention`, and absent values remain omitted. | After | | --- | | <img width="1862" height="966" alt="CleanShot 2026-09-17 at 15 11 26@2x" src="https://github.com/user-attachments/assets/8475bc8a-792c-46fc-b776-1ea20b7dfb89" /> | ## To test 1. Open `/project/<ref>/database/replication/<pipeline-id>` for a BigQuery pipeline while at least one table is completing its initial sync (or was just restarted). 2. Find that table under **Replicated tables**. 3. Confirm its **Details** cell reads in this order when all values are available: `720 MB waiting to sync · 1.3 GB WAL retention remaining · Last check-in 2 min`. 4. Confirm a temporary slot with unlimited retention shows `Unlimited WAL retention`, and a missing retention value adds no placeholder. 5. Confirm WAL warnings such as `Some changes at risk` or `Some changes lost` still appear alongside the retention value. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Replication status now displays remaining WAL retention. - Shows unlimited retention when applicable or presents finite capacity in a readable format. - Reports when retention is exhausted and changes may be at risk. - **Bug Fixes** - Invalid retention values no longer produce misleading WAL retention messages. - Replication pipeline status more clearly identifies conditions where changes may be at risk due to limited or exhausted retention. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
e3c677fc5a
commit
8511f92314
2 files changed
+54
-7
No files matched your search
+42
-7
@@ -3,7 +3,7 @@ import { describe, expect, test } from 'vitest'
|
||||
import { getTableSyncLagLabel } from './ReplicationPipelineStatus.utils'
|
||||
|
||||
describe('getTableSyncLagLabel', () => {
|
||||
test('omits healthy slot details when the table has caught up', () => {
|
||||
test('reports unlimited WAL retention for a healthy caught-up table slot', () => {
|
||||
expect(
|
||||
getTableSyncLagLabel({
|
||||
active: true,
|
||||
@@ -12,20 +12,20 @@ describe('getTableSyncLagLabel', () => {
|
||||
confirmed_flush_lsn_bytes: 0,
|
||||
safe_wal_size_bytes: null,
|
||||
})
|
||||
).toEqual([])
|
||||
).toEqual(['Unlimited WAL retention'])
|
||||
})
|
||||
|
||||
test('reports the backlog and last check-in', () => {
|
||||
test('reports the backlog, finite WAL retention, and last check-in', () => {
|
||||
expect(
|
||||
getTableSyncLagLabel({
|
||||
active: true,
|
||||
wal_status: 'reserved',
|
||||
restart_lsn_bytes: 4096,
|
||||
confirmed_flush_lsn_bytes: 2048,
|
||||
safe_wal_size_bytes: null,
|
||||
safe_wal_size_bytes: 1_363_148_800,
|
||||
reply_time_lag: 4800,
|
||||
})
|
||||
).toEqual(['2 KB waiting to sync', 'Last check-in 4.80 s'])
|
||||
).toEqual(['2 KB waiting to sync', '1.3 GB WAL retention remaining', 'Last check-in 4.80 s'])
|
||||
})
|
||||
|
||||
test('reports slot risk without treating the expected inactive connection as a fault', () => {
|
||||
@@ -35,8 +35,43 @@ describe('getTableSyncLagLabel', () => {
|
||||
wal_status: 'unreserved',
|
||||
restart_lsn_bytes: 0,
|
||||
confirmed_flush_lsn_bytes: 0,
|
||||
safe_wal_size_bytes: null,
|
||||
safe_wal_size_bytes: 0,
|
||||
})
|
||||
).toEqual(['Some changes at risk'])
|
||||
).toEqual(['0 bytes WAL retention remaining', 'Some changes at risk'])
|
||||
})
|
||||
|
||||
test('omits WAL retention when the API does not provide it', () => {
|
||||
expect(
|
||||
getTableSyncLagLabel({
|
||||
active: true,
|
||||
wal_status: 'reserved',
|
||||
restart_lsn_bytes: 0,
|
||||
confirmed_flush_lsn_bytes: 0,
|
||||
})
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
test('omits an invalid WAL retention value', () => {
|
||||
expect(
|
||||
getTableSyncLagLabel({
|
||||
active: true,
|
||||
wal_status: 'reserved',
|
||||
restart_lsn_bytes: 0,
|
||||
confirmed_flush_lsn_bytes: 0,
|
||||
safe_wal_size_bytes: Number.NaN,
|
||||
})
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
test('omits a negative WAL retention value', () => {
|
||||
expect(
|
||||
getTableSyncLagLabel({
|
||||
active: true,
|
||||
wal_status: 'reserved',
|
||||
restart_lsn_bytes: 0,
|
||||
confirmed_flush_lsn_bytes: 0,
|
||||
safe_wal_size_bytes: -1,
|
||||
})
|
||||
).toEqual([])
|
||||
})
|
||||
})
|
||||
+12
@@ -276,6 +276,18 @@ export const getTableSyncLagLabel = (metrics: SlotLagMetrics): string[] => {
|
||||
parts.push(`${formatBytes(pendingBytes, pendingBytes < 1024 ? 0 : 1)} waiting to sync`)
|
||||
}
|
||||
|
||||
const safeWalSizeBytes = metrics.safe_wal_size_bytes
|
||||
if (safeWalSizeBytes === null) {
|
||||
parts.push('Unlimited WAL retention')
|
||||
} else if (
|
||||
typeof safeWalSizeBytes === 'number' &&
|
||||
Number.isFinite(safeWalSizeBytes) &&
|
||||
safeWalSizeBytes >= 0
|
||||
) {
|
||||
const formattedBytes = formatBytes(safeWalSizeBytes, safeWalSizeBytes < 1024 ? 0 : 1)
|
||||
parts.push(`${formattedBytes} WAL retention remaining`)
|
||||
}
|
||||
|
||||
if (metrics.wal_status === 'unreserved') parts.push('Some changes at risk')
|
||||
if (metrics.wal_status === 'lost') parts.push('Some changes lost')
|
||||
|
||||
|
||||
Reference in new issue
Block a user