mirror of
https://github.com/kuhyx/diet-guard.git
synced 2026-11-10 18:07:20 +01:00
Finish the three sync bugs: gate, SIGKILL flag, and silent catches
Auditing the whole fleet for the bugs found on the desktop turned up three that were still live here. 1. `--virtual-time-budget=45000` was still in the provisioning args. The previous commit added the comment explaining why it must not be there but left the flag itself, so headless Chrome kept SIGKILLing itself (exit -9) and could still truncate a sync. Actually removed now; a provisioning run exits 0. 2. `backgroundSyncPush` gated on `settings.isConfigured` -- "has a GitHub token" -- so the WorkManager background push was skipped entirely on a device connected only to Firebase. Same defect as _autoSync's, one layer down. Either backend now counts. 3. Three swallowed exceptions, all in the sync path: the in-isolate config read, the background push itself, and `loadAccount()`. The last one is the worst -- it hid *why* provisioning failed, which is indistinguishable from "no account set" until it says so, and cost real debugging time this session. All log at warning/error with the stack trace and stay non-fatal, per the repo's no-silent-failures rule. Verified after the change, not just compiled: provisioning exits 0 and the desktop (c891b813) still holds 359 food_log records, identical to the PC daemon's, 0 missing. 522 tests, analyzer and pre-commit clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0177xwzcpfpWG2qca8Mr39q9
This commit is contained in:
parent
d388f90ed4
commit
688bd7b1de
@ -103,7 +103,6 @@ Future<bool> _provisionSyncAccount(String home, int port) async {
|
||||
'--headless=new',
|
||||
'--disable-gpu',
|
||||
'--user-data-dir=${_profileDir(home)}',
|
||||
'--virtual-time-budget=45000',
|
||||
// Surface the page's own log() output, so a failure inside the app
|
||||
// is visible in the terminal that started the provisioning run.
|
||||
'--enable-logging=stderr',
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
/// reconnect and uploads the log without the app being reopened.
|
||||
library;
|
||||
|
||||
import 'dart:developer';
|
||||
import 'package:diet_guard_app/services/app_settings_service.dart';
|
||||
import 'package:diet_guard_app/services/budget_history_service.dart';
|
||||
import 'package:diet_guard_app/services/firebase_backend.dart';
|
||||
@ -41,16 +42,38 @@ Future<bool> backgroundSyncPush({http.Client? httpClient}) async {
|
||||
final SyncSettings settings;
|
||||
try {
|
||||
settings = await SyncSettings.load();
|
||||
} on Exception {
|
||||
return false; // couldn't read config in-isolate; let WorkManager retry
|
||||
} on Exception catch (error, stackTrace) {
|
||||
log(
|
||||
'diet_guard background sync: cannot read config in-isolate',
|
||||
level: 900,
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
return false; // let WorkManager retry
|
||||
}
|
||||
// Either backend counts. `isConfigured` means "has a GitHub token", so
|
||||
// gating on it alone silently skips every background push on a device
|
||||
// connected only to Firebase.
|
||||
if (!settings.isConfigured && await openFirebase() == null) {
|
||||
log(
|
||||
'diet_guard background sync: no backend configured; nothing to push',
|
||||
level: 900,
|
||||
);
|
||||
return true; // nothing to push; don't retry
|
||||
}
|
||||
if (!settings.isConfigured) return true; // nothing to push; don't retry
|
||||
final client = createGitHubClient(settings, httpClient: httpClient);
|
||||
try {
|
||||
await runSync(await syncBackend(client));
|
||||
return true;
|
||||
} on Exception {
|
||||
return false; // offline / transient GitHub error -> retry with backoff
|
||||
} on Exception catch (error, stackTrace) {
|
||||
// Never silent: this is the only signal that a background push failed.
|
||||
log(
|
||||
'diet_guard background sync failed',
|
||||
level: 1000,
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
return false; // offline / transient error -> retry with backoff
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
/// half. On Android there is no such file.
|
||||
library;
|
||||
|
||||
import 'dart:developer';
|
||||
import 'package:crdt_sync/crdt_sync.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
@ -59,9 +60,16 @@ Future<FirebaseAccount?> loadAccount() async {
|
||||
final provisioned = await accountFromWrapper(Uri.base);
|
||||
if (provisioned != null) await saveAccount(provisioned);
|
||||
return provisioned;
|
||||
} on Object {
|
||||
// No secret service available: behave as "not configured" rather than
|
||||
// crashing the settings screen.
|
||||
} on Object catch (error, stackTrace) {
|
||||
// Still "not configured" rather than crashing the settings screen -- but
|
||||
// never silent: this hid *why* provisioning failed, which is
|
||||
// indistinguishable from "no account set" until you say so.
|
||||
log(
|
||||
'loadAccount failed; treating this device as not configured',
|
||||
level: 1000,
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user