forked from farhoodlabs/paperclip
Merge pull request #3015 from aronprins/feature/backups-configuration
feat(backups): gzip compression and tiered retention with UI controls
This commit is contained in:
@@ -216,7 +216,7 @@ export function loadConfig(): Config {
|
||||
1,
|
||||
Number(process.env.PAPERCLIP_DB_BACKUP_RETENTION_DAYS) ||
|
||||
fileDatabaseBackup?.retentionDays ||
|
||||
30,
|
||||
7,
|
||||
);
|
||||
const databaseBackupDir = resolveHomeAwarePath(
|
||||
process.env.PAPERCLIP_DB_BACKUP_DIR ??
|
||||
|
||||
+12
-6
@@ -31,6 +31,7 @@ import { setupLiveEventsWebSocketServer } from "./realtime/live-events-ws.js";
|
||||
import {
|
||||
feedbackService,
|
||||
heartbeatService,
|
||||
instanceSettingsService,
|
||||
reconcilePersistedRuntimeServicesOnStartup,
|
||||
routineService,
|
||||
} from "./services/index.js";
|
||||
@@ -621,20 +622,25 @@ export async function startServer(): Promise<StartedServer> {
|
||||
|
||||
if (config.databaseBackupEnabled) {
|
||||
const backupIntervalMs = config.databaseBackupIntervalMinutes * 60 * 1000;
|
||||
const settingsSvc = instanceSettingsService(db);
|
||||
let backupInFlight = false;
|
||||
|
||||
|
||||
const runScheduledBackup = async () => {
|
||||
if (backupInFlight) {
|
||||
logger.warn("Skipping scheduled database backup because a previous backup is still running");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
backupInFlight = true;
|
||||
try {
|
||||
// Read retention from Instance Settings (DB) so changes take effect without restart
|
||||
const generalSettings = await settingsSvc.getGeneral();
|
||||
const retention = generalSettings.backupRetention;
|
||||
|
||||
const result = await runDatabaseBackup({
|
||||
connectionString: activeDatabaseConnectionString,
|
||||
backupDir: config.databaseBackupDir,
|
||||
retentionDays: config.databaseBackupRetentionDays,
|
||||
retention,
|
||||
filenamePrefix: "paperclip",
|
||||
});
|
||||
logger.info(
|
||||
@@ -643,7 +649,7 @@ export async function startServer(): Promise<StartedServer> {
|
||||
sizeBytes: result.sizeBytes,
|
||||
prunedCount: result.prunedCount,
|
||||
backupDir: config.databaseBackupDir,
|
||||
retentionDays: config.databaseBackupRetentionDays,
|
||||
retention,
|
||||
},
|
||||
`Automatic database backup complete: ${formatDatabaseBackupResult(result)}`,
|
||||
);
|
||||
@@ -653,11 +659,11 @@ export async function startServer(): Promise<StartedServer> {
|
||||
backupInFlight = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
logger.info(
|
||||
{
|
||||
intervalMinutes: config.databaseBackupIntervalMinutes,
|
||||
retentionDays: config.databaseBackupRetentionDays,
|
||||
retentionSource: "instance-settings-db",
|
||||
backupDir: config.databaseBackupDir,
|
||||
},
|
||||
"Automatic database backups enabled",
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Db } from "@paperclipai/db";
|
||||
import { companies, instanceSettings } from "@paperclipai/db";
|
||||
import {
|
||||
DEFAULT_FEEDBACK_DATA_SHARING_PREFERENCE,
|
||||
DEFAULT_BACKUP_RETENTION,
|
||||
instanceGeneralSettingsSchema,
|
||||
type InstanceGeneralSettings,
|
||||
instanceExperimentalSettingsSchema,
|
||||
@@ -22,12 +23,14 @@ function normalizeGeneralSettings(raw: unknown): InstanceGeneralSettings {
|
||||
keyboardShortcuts: parsed.data.keyboardShortcuts ?? false,
|
||||
feedbackDataSharingPreference:
|
||||
parsed.data.feedbackDataSharingPreference ?? DEFAULT_FEEDBACK_DATA_SHARING_PREFERENCE,
|
||||
backupRetention: parsed.data.backupRetention ?? DEFAULT_BACKUP_RETENTION,
|
||||
};
|
||||
}
|
||||
return {
|
||||
censorUsernameInLogs: false,
|
||||
keyboardShortcuts: false,
|
||||
feedbackDataSharingPreference: DEFAULT_FEEDBACK_DATA_SHARING_PREFERENCE,
|
||||
backupRetention: DEFAULT_BACKUP_RETENTION,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user