release: v1.3.0 — 整站备份恢复、跨后端同步与任务中心
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s
This commit is contained in:
1 parent
b05d572221
commit
f17d79b236
72 files changed
+4312
-559
No files matched your search
@@ -0,0 +1,112 @@
|
||||
import { runBackendSyncJob } from './backend-sync'
|
||||
import { runFullExportJob } from './full-export'
|
||||
import { runFullRestoreJob } from './full-restore'
|
||||
import {
|
||||
createBackupJob,
|
||||
getBackupJob,
|
||||
markJobFailed,
|
||||
markJobRunning,
|
||||
recoverInterruptedBackupJobs,
|
||||
type BackupJob
|
||||
} from './jobs'
|
||||
|
||||
interface BackupRunnerState {
|
||||
running: boolean
|
||||
currentJobId: string | null
|
||||
}
|
||||
|
||||
const runnerState: BackupRunnerState = (globalThis as typeof globalThis & {
|
||||
__pichostBackupRunner?: BackupRunnerState
|
||||
}).__pichostBackupRunner ?? {
|
||||
running: false,
|
||||
currentJobId: null
|
||||
}
|
||||
;(globalThis as typeof globalThis & {
|
||||
__pichostBackupRunner?: BackupRunnerState
|
||||
}).__pichostBackupRunner = runnerState
|
||||
|
||||
export function isBackupRunnerBusy(): boolean {
|
||||
return runnerState.running
|
||||
}
|
||||
|
||||
function claimJobSlot(): void {
|
||||
if (runnerState.running) {
|
||||
throw new Error('BACKUP_JOB_RUNNING')
|
||||
}
|
||||
recoverInterruptedBackupJobs()
|
||||
}
|
||||
|
||||
export function cancelBackupJob(jobId: string): boolean {
|
||||
const job = getBackupJob(jobId)
|
||||
if (!job || (job.status !== 'running' && job.status !== 'pending')) {
|
||||
return false
|
||||
}
|
||||
markJobFailed(jobId, '任务已取消')
|
||||
if (runnerState.currentJobId === jobId) {
|
||||
runnerState.running = false
|
||||
runnerState.currentJobId = null
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export function scheduleBackupJob(
|
||||
job: BackupJob,
|
||||
runner: () => Promise<void>
|
||||
): void {
|
||||
if (runnerState.running) {
|
||||
throw new Error('BACKUP_JOB_RUNNING')
|
||||
}
|
||||
runnerState.running = true
|
||||
runnerState.currentJobId = job.id
|
||||
markJobRunning(job.id)
|
||||
|
||||
setImmediate(() => {
|
||||
runner()
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
runnerState.running = false
|
||||
runnerState.currentJobId = null
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function startFullExportJob(appVersion: string): BackupJob {
|
||||
claimJobSlot()
|
||||
const job = createBackupJob({
|
||||
type: 'full_export',
|
||||
message: '等待开始…'
|
||||
})
|
||||
scheduleBackupJob(job, () => runFullExportJob(job.id, appVersion))
|
||||
return getBackupJob(job.id)!
|
||||
}
|
||||
|
||||
export function startFullRestoreJob(
|
||||
archivePath: string,
|
||||
conflictMode: 'skip' | 'overwrite'
|
||||
): BackupJob {
|
||||
claimJobSlot()
|
||||
const job = createBackupJob({
|
||||
type: 'full_restore',
|
||||
message: '等待开始…',
|
||||
payload: { archivePath, conflictMode }
|
||||
})
|
||||
scheduleBackupJob(job, () => runFullRestoreJob(job.id, archivePath, { conflictMode }))
|
||||
return getBackupJob(job.id)!
|
||||
}
|
||||
|
||||
export function startBackendSyncJob(options: {
|
||||
fromBackendId: string
|
||||
toBackendId: string
|
||||
deleteSource?: boolean
|
||||
setDefault?: boolean
|
||||
dryRun?: boolean
|
||||
}): BackupJob {
|
||||
claimJobSlot()
|
||||
const job = createBackupJob({
|
||||
type: 'backend_sync',
|
||||
message: options.dryRun ? '预检中…' : '等待开始…',
|
||||
payload: options
|
||||
})
|
||||
scheduleBackupJob(job, () => runBackendSyncJob(job.id, options))
|
||||
return getBackupJob(job.id)!
|
||||
}
|
||||
Reference in new issue
Block a user