From 6682e6e62902ae04cb8344e4d2ac0ae06fe8eaa6 Mon Sep 17 00:00:00 2001 From: Jonathan Poltak Samosir Date: Tue, 4 Jun 2024 20:56:01 +0700 Subject: [PATCH] Set up alarm to periodically check that DB data loss flag exists - ping sentry if not --- src/background-script/constants.ts | 2 - src/background-script/db-data-loss-check.ts | 40 +++++++++++++++++++ src/background-script/index.ts | 22 +++++----- .../quick-and-dirty-migrations/index.test.ts | 1 + .../quick-and-dirty-migrations/index.ts | 17 ++++---- src/background-script/setup.ts | 15 ++++++- 6 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 src/background-script/db-data-loss-check.ts diff --git a/src/background-script/constants.ts b/src/background-script/constants.ts index 6fb1cc2f7e..5cc3fe2de7 100644 --- a/src/background-script/constants.ts +++ b/src/background-script/constants.ts @@ -6,5 +6,3 @@ export const UNINSTALL_URL = `${API_HOST}/uninstall` * Percentage of quota usage where we want to warn users with a notification. */ export const QUOTA_USAGE_WARN_PERC = 80 - -export const DB_DATA_LOSS_FLAG = { name: 'STORAGE_CHECK_FLAG', postId: -1 } diff --git a/src/background-script/db-data-loss-check.ts b/src/background-script/db-data-loss-check.ts new file mode 100644 index 0000000000..141ab93351 --- /dev/null +++ b/src/background-script/db-data-loss-check.ts @@ -0,0 +1,40 @@ +import type Dexie from 'dexie' +import type { captureException } from 'src/util/raven' + +/* + * This exists as we had a suspicion that sometimes browsers would forcefully evict all extension data. + * To in/validate that we put this flag and periodically check it to see if it's still there. In + * the case of a full data eviction, it should be gone. + * + * socialTags collection chosen as it's long abandoned but still exists in the DB schema. Thus less work. + */ + +export const DB_DATA_LOSS_CHECK_ALARM_NAME = 'db-data-loss-check' +export const DB_DATA_LOSS_FLAG = { name: 'STORAGE_CHECK_FLAG', postId: -1 } + +interface Params { + db: Dexie + captureException: typeof captureException +} + +async function isDataLoss({ db }: Params): Promise { + let [existing] = await db + .table('socialTags') + .where({ postId: DB_DATA_LOSS_FLAG.postId }) + .primaryKeys() + return !existing +} + +export async function checkDataLoss(params: Params) { + if (await isDataLoss(params)) { + await params.captureException( + new Error('OwnError: Data loss flag was not found in DB'), + ) + } +} + +export async function ensureDataLossFlagSet(params: Params) { + if (await isDataLoss(params)) { + await params.db.table('socialTags').add(DB_DATA_LOSS_FLAG) + } +} diff --git a/src/background-script/index.ts b/src/background-script/index.ts index b41882a64e..1a0f75f451 100644 --- a/src/background-script/index.ts +++ b/src/background-script/index.ts @@ -37,13 +37,12 @@ import { getLocalStorage, setLocalStorage } from 'src/util/storage' import { MISSING_PDF_QUERY_PARAM } from 'src/dashboard-refactor/constants' import type { BackgroundModules } from './setup' import type { InPageUIContentScriptRemoteInterface } from 'src/in-page-ui/content_script/types' -import { captureException } from 'src/util/raven' +import type { captureException } from 'src/util/raven' import { checkStripePlan } from '@worldbrain/memex-common/lib/subscriptions/storage' import type { AnalyticsCoreInterface } from '@worldbrain/memex-common/lib/analytics/types' import { CLOUDFLARE_WORKER_URLS } from '@worldbrain/memex-common/lib/content-sharing/storage/constants' import checkBrowser from 'src/util/check-browser' -import type Dexie from 'dexie' -import { DB_DATA_LOSS_FLAG } from './constants' +import { ensureDataLossFlagSet } from './db-data-loss-check' interface Dependencies { localExtSettingStore: BrowserSettingsStore @@ -52,6 +51,7 @@ interface Dependencies { > urlNormalizer: URLNormalizer storageChangesMan: StorageChangesManager + captureException: typeof captureException storageAPI: Storage.Static runtimeAPI: Runtime.Static browserAPIs: Browser @@ -133,10 +133,10 @@ class BackgroundScript { // Store the timestamp of when the extension was installed await this.deps.localExtSettingStore.set('installTimestamp', Date.now()) - // Add this to an unused table to periodically check and see if all data has ever been evicted - await (this.deps.storageManager.backend['dexie'] as Dexie) - .table('socialTags') - .add(DB_DATA_LOSS_FLAG) + await ensureDataLossFlagSet({ + captureException: this.deps.captureException, + db: this.deps.storageManager.backend['dexie'], + }) // Disable PDF integration by default await this.deps.syncSettingsStore.pdfIntegration.set( @@ -274,6 +274,7 @@ class BackgroundScript { bgModules: this.deps.bgModules, storex: this.deps.storageManager, db: this.deps.storageManager.backend['dexieInstance'], + captureException: this.deps.captureException, localStorage: this.deps.storageAPI.local, normalizeUrl: this.deps.urlNormalizer, syncSettingsStore: this.deps.syncSettingsStore, @@ -299,6 +300,7 @@ class BackgroundScript { bgModules: this.deps.bgModules, storex: this.deps.storageManager, db: this.deps.storageManager.backend['dexieInstance'], + captureException: this.deps.captureException, localStorage: this.deps.storageAPI.local, normalizeUrl: this.deps.urlNormalizer, syncSettingsStore: this.deps.syncSettingsStore, @@ -369,7 +371,7 @@ class BackgroundScript { `Error encountered attempting to teardown content scripts for extension update on tab "${tab.id}" - url "${tab.url}":`, err.message, ) - captureException(err) + this.deps.captureException(err) }, }, ) @@ -378,7 +380,7 @@ class BackgroundScript { 'Error encountered attempting to teardown content scripts for extension update:', err.message, ) - captureException(err) + this.deps.captureException(err) } // This call prompts the extension to reload, updating the scripts to the newest versions @@ -421,7 +423,7 @@ class BackgroundScript { }, ) } catch (err) { - captureException(err) + this.deps.captureException(err) } } diff --git a/src/background-script/quick-and-dirty-migrations/index.test.ts b/src/background-script/quick-and-dirty-migrations/index.test.ts index c73d01d307..ffb37aefb4 100644 --- a/src/background-script/quick-and-dirty-migrations/index.test.ts +++ b/src/background-script/quick-and-dirty-migrations/index.test.ts @@ -22,6 +22,7 @@ async function setupTest() { db: setup.storageManager.backend['dexieInstance'], localStorage: setup.browserAPIs.storage.local, bgModules: setup.backgroundModules, + captureException: () => {}, syncSettingsStore: setup.backgroundModules.bgScript.deps.syncSettingsStore, localExtSettingStore: diff --git a/src/background-script/quick-and-dirty-migrations/index.ts b/src/background-script/quick-and-dirty-migrations/index.ts index cc6e5263f6..038fad6b9f 100644 --- a/src/background-script/quick-and-dirty-migrations/index.ts +++ b/src/background-script/quick-and-dirty-migrations/index.ts @@ -35,11 +35,13 @@ import type { SyncSettingsByFeature } from 'src/sync-settings/background/types' import { HIGHLIGHT_COLORS_DEFAULT } from '@worldbrain/memex-common/lib/common-ui/components/highlightColorPicker/constants' import type { CustomListTree } from '@worldbrain/memex-common/lib/types/core-data-types/client' import type { Template } from 'src/copy-paster/types' -import { DB_DATA_LOSS_FLAG } from '../constants' +import { ensureDataLossFlagSet } from '../db-data-loss-check' +import type { captureException } from 'src/util/raven' export interface MigrationProps { db: Dexie storex: Storex + captureException: typeof captureException normalizeUrl: URLNormalizer localStorage: Storage.LocalStorageArea bgModules: Pick< @@ -75,14 +77,11 @@ export const migrations: Migrations = { * To in/validate that we put this flag and periodically check it to see if it's still there. In * the case of a full data eviction, it should be gone. */ - [MIGRATION_PREFIX + 'add-db-data-loss-check-flag-01']: async ({ db }) => { - let [existing] = await db - .table('socialTags') - .where({ postId: DB_DATA_LOSS_FLAG.postId }) - .primaryKeys() - if (!existing) { - await db.table('socialTags').add(DB_DATA_LOSS_FLAG) - } + [MIGRATION_PREFIX + 'add-db-data-loss-check-flag-01']: async ({ + db, + captureException, + }) => { + await ensureDataLossFlagSet({ db, captureException }) }, /* * This exists as we released the templates with a new order field, same as cuomstListTrees, diff --git a/src/background-script/setup.ts b/src/background-script/setup.ts index 9f6fd6aea7..3e1a55bd75 100644 --- a/src/background-script/setup.ts +++ b/src/background-script/setup.ts @@ -62,7 +62,7 @@ import SummarizeBackground from 'src/summarization-llm/background' import ActivityStreamsBackground from 'src/activity-streams/background' import { SyncSettingsBackground } from 'src/sync-settings/background' import type { AuthServices, Services } from 'src/services/types' -import type { captureException } from 'src/util/raven' +import { captureException } from 'src/util/raven' import { PDFBackground } from 'src/pdf/background' // import { FirebaseUserMessageService } from '@worldbrain/memex-common/lib/user-messages/service/firebase' // import { UserMessageService } from '@worldbrain/memex-common/lib/user-messages/service/types' @@ -109,6 +109,10 @@ import { import checkBrowser from 'src/util/check-browser' import { AUTOMATED_BACKUP_ALARM_NAME } from 'src/backup-restore/background/constants' import { AlarmJob, setupAlarms } from './alarms' +import { + DB_DATA_LOSS_CHECK_ALARM_NAME, + checkDataLoss, +} from './db-data-loss-check' export interface BackgroundModules { analyticsBG: AnalyticsCoreInterface @@ -582,6 +586,7 @@ export function createBackgroundModules(options: { browserAPIs: options.browserAPIs, storageAPI: options.browserAPIs.storage, tabsAPI: options.browserAPIs.tabs, + captureException: options.captureException, localExtSettingStore, syncSettingsStore, storageManager, @@ -793,6 +798,14 @@ export async function setupBackgroundModules( job: () => backgroundModules.personalCloud.actionQueue.executePendingActions(), }, + [DB_DATA_LOSS_CHECK_ALARM_NAME]: { + alarmDefinition: { periodInMinutes: 15 }, + job: () => + checkDataLoss({ + captureException, + db: storageManager.backend['dexie'], + }), + }, } if (checkBrowser() !== 'firefox') {