New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#7784: skip waiting for managed storage after initial wait #7790
Conversation
@@ -239,21 +239,6 @@ function useRequiredPartnerAuth(): RequiredPartnerState { | |||
authMethodOverride === "partner-oauth2" || | |||
authMethodOverride === "partner-token"; | |||
|
|||
console.debug("useRequiredPartnerAuth", { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accidentally left this in the other PR
@fregante thoughts on how to fix onChanged errors in tests?: https://github.com/pixiebrix/pixiebrix-extension/pull/7790/files#diff-da2fdc70c5e193c8b4888da54a7cb919a8bd98a8196358ac0d300b60b18922bbR52 |
This comment was marked as outdated.
This comment was marked as outdated.
Oh it seems that the whole Dropping this line fixes the issue, but it breaks the LogTable story
|
src/background/installer.ts
Outdated
@@ -321,9 +323,14 @@ async function setUninstallURL(): Promise<void> { | |||
} | |||
|
|||
function initInstaller() { | |||
browser.runtime.onStartup.addListener(async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that onStartup
does not mean "on extension start", but "on browser start"
This means that this won't run when the user first installs the extension or when they re-enable it.
In MV2, all code is run at the start.
in MV3, you might want to try https://github.com/fregante/webext-events/blob/main/source/on-extension-start.md
@fregante thanks for the help tracking down the onChanged issue. This should be ready for another review. I ended up using SessionValue instead of onSessionStart to avoid the setInterval |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7790 +/- ##
==========================================
+ Coverage 72.28% 72.31% +0.03%
==========================================
Files 1271 1271
Lines 39697 39748 +51
Branches 7372 7380 +8
==========================================
+ Hits 28693 28743 +50
- Misses 11004 11005 +1 ☔ View full report in Codecov by Sentry. |
|
||
type HookState = { | ||
data: Nullishable<ManagedStorageState>; | ||
isLoading: boolean; | ||
}; | ||
|
||
// NOTE: can't share subscribe methods across generators currently for useAsyncExternalStore because it maintains | ||
// a map of subscriptions to state controllers. See https://github.com/pixiebrix/pixiebrix-extension/issues/7789 | ||
function subscribe(callback: () => void): () => void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved here from managedStorage to prevent accidentally using across multiple hooks given the useAsyncExternalStore footgun
src/background/installer.ts
Outdated
// Using our own session value vs. webext-events because onExtensionStart has a 100ms delay | ||
// https://github.com/fregante/webext-events/blob/main/source/on-extension-start.ts#L56 | ||
|
||
// Can't use onStartup because it doesn't mean "on extension start", but "on browser profile start". | ||
// Events registered onStartup won't run when the user first installs or when they re-enable the extension. | ||
// See: https://developer.chrome.com/docs/extensions/reference/api/runtime#event-onStartup | ||
|
||
if (await initialized.get()) { | ||
// Session already initialized | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm generally against inlining logic that is reused, e.g. logic like once
, memoize
, throttle
and the whole managed storage initialization logic. Doing otherwise leads to mixing business logic where it's not expected.
I think this call could be:
const initSessionOnce = pMemoize(async () => {
//
}, {
// initSessionOnce has no arguments, so only one value is stored
cache: new SessionMap('managedstorageinit', import.meta.url)
})
or
const oncePerSession = (key, url, fn) => pMemoize(fn, {
cache: new SessionMap(key, url)
})
const initSessionOnce = oncePerSession('managedstorageinit', import.meta.url, async () => {
//
});
const waitController = new AbortController(); | ||
// Skip polling if it becomes initialized while waiting | ||
initializationTimestamp.onChanged( | ||
waitController.abort, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
waitController.abort, | |
waitController.abort.bind(waitController), |
But in reality this cannot happen. Line 185 (initializationTimestamp.set
) cannot be reached by another process while this one is running because waitForInitialManagedStorage
is only run once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's related to the misunderstanding here? -- that the timestamp is using local storage to be available across contexts: #7790 (comment)
The abort logic in the waitForInitialManagedStorage
handles the case where:
- Background page starts up and is starts polling for managed storage
- Extension Console Page Starts up and starts polling
- Background page page finished polling
- The new abort controller allows the Extension Console page quit polling because it knows the Background Page already polled the 4.5 seconds
// Call watchDelayedStorageInitialization to handle case where storage is not immediately available within timeout. | ||
// We might consider putting watchStorageInitialization in initManagedStorage, but having a non-terminating | ||
// interval complicates testing. | ||
void initManagedStorage().then(async () => watchDelayedStorageInitialization()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to installer
@@ -305,8 +304,9 @@ async function collectUserSummary(): Promise<UserSummary> { | |||
} | |||
|
|||
async function init(): Promise<void> { | |||
if ((await isLinked()) && (await allowsTrack())) { | |||
const client = await getLinkedApiClient(); | |||
const client = await maybeGetLinkedApiClient(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix race condition
@@ -58,6 +59,19 @@ export class SessionMap<Value extends JsonValue> { | |||
return `${this.key}::${this.url}::${secondaryKey}` as ManualStorageKey; | |||
} | |||
|
|||
async has(secondaryKey: string): Promise<boolean> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
has
is required to be used a cache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙌
async () => { | ||
await resetManagedStorageInitializationState(); | ||
await initManagedStorage(); | ||
void watchForDelayedStorageInitialization(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Very readable now
src/testUtils/testAfterEnv.ts
Outdated
jest.setMock("webext-detect-page", detectPageMock); | ||
|
||
// For some reason, throwIfAborted is not available in Jest environment even though it appears to be in JSDOM | ||
// https://github.com/jsdom/jsdom/blob/2f8a7302a43fff92f244d5f3426367a8eb2b8896/lib/jsdom/living/aborting/AbortSignal-impl.js#L24 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it's unfortunate. More info in FixJsdomEnvironment.js and testEnv.js
No loom links were found in the first post. Please add one there if you'd like to it to appear on Slack. Do not edit this comment manually. |
What does this PR do?
Remaining Work
Reviewer Tips
managedStorage.ts
installer.ts
Future Work
Checklist
src/tsconfig.strictNullChecks.json
(if possible): N/A