chore: restore autocancellation

This commit is contained in:
Ben Allfree 2022-11-20 04:20:31 -08:00
parent b5d3cf48a6
commit 0a09500439
5 changed files with 12 additions and 95 deletions

View File

@ -24,11 +24,6 @@ export const createPbClient = (url: string) => {
)
const client = new PocketBase(url)
client.beforeSend = (url: string, reqConfig: { [_: string]: any }) => {
// dbg(reqConfig)
delete reqConfig.signal
return reqConfig
}
const adminAuthViaEmail = safeCatch(
`adminAuthViaEmail`,

View File

@ -1,11 +1,13 @@
import {
assertTruthy,
BackupRecord,
BackupStatus,
createTimerManager,
InstanceBackupJobPayload,
InstanceRestoreJobPayload,
JobCommands,
} from '@pockethost/common'
import Bottleneck from 'bottleneck'
import { PocketbaseClientApi } from '../db/PbClient'
import { backupInstance } from '../util/backupInstance'
import { dbg } from '../util/dbg'
@ -60,6 +62,7 @@ export const createBackupService = async (
)
const tm = createTimerManager({})
const limiter = new Bottleneck({ maxConcurrent: 1 })
tm.repeat(async () => {
const backupRec = await client.getNextBackupJob()
if (!backupRec) {
@ -67,8 +70,10 @@ export const createBackupService = async (
return true
}
const instance = await client.getInstance(backupRec.instanceId)
const _update = (fields: Partial<BackupRecord>) =>
limiter.schedule(() => client.updateBackup(backupRec.id, fields))
try {
await client.updateBackup(backupRec.id, {
await _update({
status: BackupStatus.Running,
})
let progress = backupRec.progress || {}
@ -78,12 +83,12 @@ export const createBackupService = async (
(_progress) => {
progress = { ...progress, ..._progress }
dbg(_progress)
return client.updateBackup(backupRec.id, {
return _update({
progress,
})
}
)
await client.updateBackup(backupRec.id, {
await _update({
bytes,
status: BackupStatus.FinishedSuccess,
})
@ -95,7 +100,7 @@ export const createBackupService = async (
}
return s
})()
await client.updateBackup(backupRec.id, {
await _update({
status: BackupStatus.FinishedError,
message,
})

View File

@ -39,10 +39,6 @@ export type PocketbaseClientApi = ReturnType<typeof createPocketbaseClient>
export const createPocketbaseClient = (url: string) => {
const client = new PocketBase(url)
client.beforeSend = (url, reqConfig) => {
delete reqConfig.signal
return reqConfig
}
const { authStore } = client

View File

@ -1,92 +1,13 @@
<script lang="ts">
import { PUBLIC_APP_DOMAIN } from '$env/static/public'
import { client } from '$src/pocketbase'
import { createCleanupManagerSync } from '$util/CleanupManager'
import {
BackupStatus,
type BackupRecord,
type InstancesRecord,
type RecordId
} from '@pockethost/common'
import { reduce, sortBy } from '@s-libs/micro-dash'
import prettyBytes from 'pretty-bytes'
import { onDestroy, onMount } from 'svelte'
import { writable } from 'svelte/store'
import type { InstancesRecord } from '@pockethost/common'
export let instance: InstancesRecord
const cm = createCleanupManagerSync()
const backups = writable<BackupRecord[]>([])
let isBackingUp = false
onMount(async () => {
const { watchBackupsByInstanceId } = client()
watchBackupsByInstanceId(instance.id, (r) => {
// console.log(`Handling backup update`, r)
const { action, record } = r
const _backups = reduce(
$backups,
(c, b) => {
c[b.id] = b
return c
},
{} as { [_: RecordId]: BackupRecord }
)
_backups[record.id] = record
isBackingUp = false
backups.set(
sortBy(_backups, (e) => {
isBackingUp ||=
e.status !== BackupStatus.FinishedError && e.status !== BackupStatus.FinishedSuccess
return Date.parse(e.created)
}).reverse()
)
// console.log(record.id)
}).then(cm.add)
})
onDestroy(cm.cleanupAll)
const startRestore = () => {
const { createInstanceBackupJob } = client()
createInstanceBackupJob(instance.id)
}
let sourceBackupId = ''
</script>
<div class="py-4">
<h2>Restore</h2>
{#if PUBLIC_APP_DOMAIN.toString().endsWith('.io')}
Contact support to perform a restore.
{/if}
{#if PUBLIC_APP_DOMAIN.toString().endsWith('.test')}
{#if $backups.length === 0}
You must create a backup first.
{/if}
{#if $backups.length > 0}
<select value={sourceBackupId}>
<option value=""> -- choose snapshot -- </option>
{#each $backups as { id, bytes, updated, platform, version, status, message, progress }}
{#if status === BackupStatus.FinishedSuccess}
<option value={id}>
{platform}:{version} ({prettyBytes(bytes)}) - Finished {new Date(updated)}#
</option>
{/if}
{/each}
</select>
<div class="text-center py-5">
<div class="text-danger">
Notice: Your instance will be placed in maintenance mode and then backed up before
restoring the selected snapshot.
</div>
<button class="btn btn-light" on:click={() => startRestore()} disabled={!sourceBackupId}>
<i class="bi bi-safe" /> Restore Now
</button>
</div>
{/if}
{/if}
Contact support to perform a restore.
</div>
<style lang="scss">

View File

@ -140,7 +140,7 @@ open https://pockethost.io
- [x] fix: more helpful error message when backup fails for nonexistent instance
- [x] chore: move version number to base package.json
- [ ] chore: refactor logging and async helpers
- [ ] chore: restore autocancellation
- [x] chore: restore autocancellation
- [x] chore: rebuild with go 1.19.3 and include in bin name
- [ ] fix: Disallow backups if data dir doesn't exist