fix(standalone): crash in logs due to refresh

This commit is contained in:
Elian Doran
2026-04-12 18:43:03 +03:00
parent 89b3dec84a
commit 9f24a44e15
6 changed files with 32 additions and 19 deletions

View File

@@ -72,17 +72,7 @@ export default class StandaloneBackupService extends BackupService {
}
}
override getExistingBackups(): DatabaseBackup[] {
// This method is synchronous in the interface, but OPFS is async.
// Return empty array - the UI can use an async method if needed.
// A future improvement could cache the backup list.
return [];
}
/**
* Async version of getExistingBackups for use in standalone UI.
*/
async getExistingBackupsAsync(): Promise<DatabaseBackup[]> {
override async getExistingBackups(): Promise<DatabaseBackup[]> {
if (!this.isOpfsAvailable()) {
return [];
}
@@ -100,7 +90,6 @@ export default class StandaloneBackupService extends BackupService {
continue;
}
// OPFS doesn't provide mtime, so we parse from filename or use current time
const file = await (handle as FileSystemFileHandle).getFile();
backups.push({
fileName: name,

View File

@@ -42,12 +42,36 @@ export default class StandaloneLogService extends FileBasedLogService {
}
const fileHandle = await this.logDir!.getFileHandle(fileName, { create: true });
this.currentFile = await fileHandle.createSyncAccessHandle();
// Try to create sync access handle with retry logic for worker restarts
// Previous worker may have left handle open before being terminated
const maxRetries = 3;
const retryDelay = 100;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
this.currentFile = await fileHandle.createSyncAccessHandle();
break;
} catch (error) {
if (attempt === maxRetries - 1) {
// Last attempt failed - fall back to console-only logging
console.warn("[LogService] Could not open log file, using console-only logging:", error);
this.currentFile = null;
this.currentFileName = "";
return;
}
// Wait before retrying - previous handle may be released
await new Promise(resolve => setTimeout(resolve, retryDelay * (attempt + 1)));
}
}
this.currentFileName = fileName;
// Seek to end for appending
const size = this.currentFile.getSize();
this.currentFile.truncate(size); // No-op, but ensures we're at the right position
if (this.currentFile) {
const size = this.currentFile.getSize();
this.currentFile.truncate(size); // No-op, but ensures we're at the right position
}
}
protected override closeLogFile(): void {

View File

@@ -12,7 +12,7 @@ export default class ServerBackupService extends BackupService {
super(options);
}
override getExistingBackups(): DatabaseBackup[] {
override async getExistingBackups(): Promise<DatabaseBackup[]> {
if (!fs.existsSync(dataDir.BACKUP_DIR)) {
return [];
}

View File

@@ -1,7 +1,7 @@
import type { BackupDatabaseNowResponse, DatabaseBackup } from "@triliumnext/commons";
import { getBackup } from "../../services/backup.js";
function getExistingBackups(): DatabaseBackup[] {
async function getExistingBackups(): Promise<DatabaseBackup[]> {
return getBackup().getExistingBackups();
}

View File

@@ -205,7 +205,7 @@ export function buildSharedApiRoutes({ route, asyncRoute, apiRoute, asyncApiRout
asyncApiRoute(GET, "/api/backend-log", backendLogRoute.getBackendLog);
// Backup routes
apiRoute(GET, "/api/database/backups", backupRoute.getExistingBackups);
asyncApiRoute(GET, "/api/database/backups", backupRoute.getExistingBackups);
asyncApiRoute(PST, "/api/database/backup-database", backupRoute.backupDatabase);
apiRoute(GET, "/api/other/icon-usage", otherRoute.getIconUsage);

View File

@@ -39,7 +39,7 @@ export default abstract class BackupService {
/**
* Get list of existing backups.
*/
abstract getExistingBackups(): DatabaseBackup[];
abstract getExistingBackups(): Promise<DatabaseBackup[]>;
/**
* Run the scheduled backup checks for daily, weekly, and monthly backups.