mirror of
https://github.com/cupcakearmy/autorestic.git
synced 2025-01-10 09:06:24 +00:00
do not allow multiple instances
This commit is contained in:
parent
f9c645120b
commit
1520e10a59
@ -4,11 +4,11 @@ import minimist from 'minimist'
|
|||||||
import { init } from './config'
|
import { init } from './config'
|
||||||
import handlers, { error, help } from './handlers'
|
import handlers, { error, help } from './handlers'
|
||||||
import { Config } from './types'
|
import { Config } from './types'
|
||||||
|
import { readLock, writeLock, unlock } from './lock'
|
||||||
|
|
||||||
|
|
||||||
process.on('uncaughtException', err => {
|
process.on('uncaughtException', err => {
|
||||||
console.log(err.message)
|
console.log(err.message)
|
||||||
|
unlock()
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -36,6 +36,17 @@ export let config: Config
|
|||||||
async function main() {
|
async function main() {
|
||||||
config = init()
|
config = init()
|
||||||
|
|
||||||
|
// Don't let 2 instances run on the same config
|
||||||
|
const lock = readLock()
|
||||||
|
if (lock.running) {
|
||||||
|
console.log('An instance of autorestic is already running for this config file'.red)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeLock({
|
||||||
|
...lock,
|
||||||
|
running: true,
|
||||||
|
})
|
||||||
|
|
||||||
// For dev
|
// For dev
|
||||||
// return await handlers['cron']([], { ...flags, all: true })
|
// return await handlers['cron']([], { ...flags, all: true })
|
||||||
|
|
||||||
@ -46,6 +57,7 @@ async function main() {
|
|||||||
|
|
||||||
const fn = handlers[command] || error
|
const fn = handlers[command] || error
|
||||||
await fn(args, flags)
|
await fn(args, flags)
|
||||||
|
unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
40
src/cron.ts
40
src/cron.ts
@ -1,49 +1,21 @@
|
|||||||
import fs from 'fs'
|
|
||||||
|
|
||||||
import CronParser from 'cron-parser'
|
import CronParser from 'cron-parser'
|
||||||
|
|
||||||
import { config } from './autorestic'
|
import { config } from './autorestic'
|
||||||
import { checkAndConfigureBackendsForLocations } from './backend'
|
import { checkAndConfigureBackendsForLocations } from './backend'
|
||||||
import { Location, Lockfile } from './types'
|
import { Location } from './types'
|
||||||
import { backupLocation } from './backup'
|
import { backupLocation } from './backup'
|
||||||
import { pathRelativeToConfigFile } from './utils'
|
import { readLock, writeLock } from './lock'
|
||||||
|
|
||||||
|
|
||||||
const getLockFileName = () => {
|
|
||||||
const LOCK_FILE = '.autorestic.lock'
|
|
||||||
return pathRelativeToConfigFile(LOCK_FILE)
|
|
||||||
}
|
|
||||||
|
|
||||||
const readLock = (): Lockfile => {
|
|
||||||
const name = getLockFileName()
|
|
||||||
let lock = {}
|
|
||||||
try {
|
|
||||||
lock = JSON.parse(fs.readFileSync(name, { encoding: 'utf-8' }))
|
|
||||||
} catch { }
|
|
||||||
return lock
|
|
||||||
}
|
|
||||||
const writeLock = (diff: Lockfile = {}) => {
|
|
||||||
const name = getLockFileName()
|
|
||||||
const newLock = Object.assign(
|
|
||||||
readLock(),
|
|
||||||
diff
|
|
||||||
)
|
|
||||||
fs.writeFileSync(name, JSON.stringify(newLock, null, 2), { encoding: 'utf-8' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const runCronForLocation = (name: string, location: Location) => {
|
const runCronForLocation = (name: string, location: Location) => {
|
||||||
const lock = readLock()[name]
|
const lock = readLock()
|
||||||
const parsed = CronParser.parseExpression(location.cron || '')
|
const parsed = CronParser.parseExpression(location.cron || '')
|
||||||
const last = parsed.prev()
|
const last = parsed.prev()
|
||||||
|
|
||||||
if (!lock || last.toDate().getTime() > lock.lastRun) {
|
if (!lock.crons[name] || last.toDate().getTime() > lock.crons[name].lastRun) {
|
||||||
backupLocation(name, location)
|
backupLocation(name, location)
|
||||||
writeLock({
|
lock.crons[name] = { lastRun: Date.now() }
|
||||||
[name]: {
|
writeLock(lock)
|
||||||
...lock,
|
|
||||||
lastRun: Date.now()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
console.log(`${name.yellow} ▶ Skipping. Sheduled for: ${parsed.next().toString().underline.blue}`)
|
console.log(`${name.yellow} ▶ Skipping. Sheduled for: ${parsed.next().toString().underline.blue}`)
|
||||||
}
|
}
|
||||||
|
32
src/lock.ts
Normal file
32
src/lock.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
|
import { pathRelativeToConfigFile } from "./utils"
|
||||||
|
import { Lockfile } from "./types"
|
||||||
|
|
||||||
|
export const getLockFileName = () => {
|
||||||
|
const LOCK_FILE = '.autorestic.lock'
|
||||||
|
return pathRelativeToConfigFile(LOCK_FILE)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const readLock = (): Lockfile => {
|
||||||
|
const name = getLockFileName()
|
||||||
|
let lock = {
|
||||||
|
running: false,
|
||||||
|
crons: {}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
lock = JSON.parse(fs.readFileSync(name, { encoding: 'utf-8' }))
|
||||||
|
} catch { }
|
||||||
|
return lock
|
||||||
|
}
|
||||||
|
export const writeLock = (lock: Lockfile) => {
|
||||||
|
const name = getLockFileName()
|
||||||
|
fs.writeFileSync(name, JSON.stringify(lock, null, 2), { encoding: 'utf-8' })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const unlock = () => {
|
||||||
|
writeLock({
|
||||||
|
...readLock(),
|
||||||
|
running: false,
|
||||||
|
})
|
||||||
|
}
|
@ -93,9 +93,12 @@ export type Config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Lockfile = {
|
export type Lockfile = {
|
||||||
|
running: boolean
|
||||||
|
crons: {
|
||||||
[name: string]: {
|
[name: string]: {
|
||||||
lastRun: number
|
lastRun: number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type Flags = { [arg: string]: any }
|
export type Flags = { [arg: string]: any }
|
||||||
|
Loading…
Reference in New Issue
Block a user