Skip to content
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

feat(27254): implement new remote-feature-flag-controller #4931

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

DDDDDanica
Copy link

@DDDDDanica DDDDDanica commented Nov 14, 2024

Explanation

Following the ADR here

Adds a new controller, remote-feature-flag-controller that fetches the remote feature flags and provide cache solution for consumers.

References

Related to #27254

Changelog

@metamask/remote-feature-flag-controller

ADDED: Initial release

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've highlighted breaking changes using the "BREAKING" category above as appropriate
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch 6 times, most recently from 78af7f4 to cd93f7a Compare November 15, 2024 03:13
Copy link

socket-security bot commented Nov 15, 2024

No dependency changes detected. Learn more about Socket for GitHub ↗︎

👍 No dependency changes detected in pull request

@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch from cd93f7a to 82f7997 Compare November 16, 2024 03:42
@DDDDDanica DDDDDanica self-assigned this Nov 16, 2024
@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch 2 times, most recently from 78ca22b to a7a3cf1 Compare November 19, 2024 11:53
@DDDDDanica DDDDDanica marked this pull request as ready for review November 19, 2024 23:04
@DDDDDanica DDDDDanica requested a review from a team as a code owner November 19, 2024 23:04
@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch 9 times, most recently from 0519340 to fcc71a0 Compare November 20, 2024 12:19
@DDDDDanica
Copy link
Author

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "19.0.0-preview-fcc71a0",
  "@metamask-previews/address-book-controller": "6.0.1-preview-fcc71a0",
  "@metamask-previews/announcement-controller": "7.0.1-preview-fcc71a0",
  "@metamask-previews/approval-controller": "7.1.1-preview-fcc71a0",
  "@metamask-previews/assets-controllers": "44.0.1-preview-fcc71a0",
  "@metamask-previews/base-controller": "7.0.2-preview-fcc71a0",
  "@metamask-previews/build-utils": "3.0.1-preview-fcc71a0",
  "@metamask-previews/chain-controller": "0.1.3-preview-fcc71a0",
  "@metamask-previews/composable-controller": "9.0.1-preview-fcc71a0",
  "@metamask-previews/controller-utils": "11.4.3-preview-fcc71a0",
  "@metamask-previews/ens-controller": "15.0.0-preview-fcc71a0",
  "@metamask-previews/eth-json-rpc-provider": "4.1.6-preview-fcc71a0",
  "@metamask-previews/gas-fee-controller": "22.0.1-preview-fcc71a0",
  "@metamask-previews/json-rpc-engine": "10.0.1-preview-fcc71a0",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.5-preview-fcc71a0",
  "@metamask-previews/keyring-controller": "18.0.0-preview-fcc71a0",
  "@metamask-previews/logging-controller": "6.0.2-preview-fcc71a0",
  "@metamask-previews/message-manager": "11.0.1-preview-fcc71a0",
  "@metamask-previews/multichain": "0.0.0-preview-fcc71a0",
  "@metamask-previews/name-controller": "8.0.1-preview-fcc71a0",
  "@metamask-previews/network-controller": "22.0.2-preview-fcc71a0",
  "@metamask-previews/notification-controller": "7.0.0-preview-fcc71a0",
  "@metamask-previews/notification-services-controller": "0.13.0-preview-fcc71a0",
  "@metamask-previews/permission-controller": "11.0.3-preview-fcc71a0",
  "@metamask-previews/permission-log-controller": "3.0.1-preview-fcc71a0",
  "@metamask-previews/phishing-controller": "12.3.0-preview-fcc71a0",
  "@metamask-previews/polling-controller": "12.0.1-preview-fcc71a0",
  "@metamask-previews/preferences-controller": "14.0.0-preview-fcc71a0",
  "@metamask-previews/profile-sync-controller": "1.0.2-preview-fcc71a0",
  "@metamask-previews/queued-request-controller": "7.0.1-preview-fcc71a0",
  "@metamask-previews/rate-limit-controller": "6.0.1-preview-fcc71a0",
  "@metamask-previews/selected-network-controller": "19.0.0-preview-fcc71a0",
  "@metamask-previews/signature-controller": "22.0.0-preview-fcc71a0",
  "@metamask-previews/transaction-controller": "39.0.0-preview-fcc71a0",
  "@metamask-previews/user-operation-controller": "18.0.0-preview-fcc71a0"
}

@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch 6 times, most recently from 153ebc9 to 0fab160 Compare November 21, 2024 21:20
@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch from 977ddbf to 276357d Compare November 26, 2024 11:46
@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch from 276357d to b25f847 Compare November 26, 2024 12:18
@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch from 7f893dc to a09cd92 Compare November 26, 2024 16:04
Copy link
Contributor

@danjm danjm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything looks good to me, except I have those last questions about the approach to error handling.

@joaoloureirop joaoloureirop requested a review from a team November 26, 2024 19:27
joaoloureirop
joaoloureirop previously approved these changes Nov 26, 2024
Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more suggestions. After that I think we are good here.

@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch 6 times, most recently from f13e7b4 to 6ea8e51 Compare November 27, 2024 17:14
@danjm
Copy link
Contributor

danjm commented Nov 27, 2024

I've coded a proposed alternative to service error handling, can be found here #4995

@DDDDDanica DDDDDanica force-pushed the feature/27254-feature-flag-controller branch from 6ea8e51 to e5e0b5c Compare November 27, 2024 22:41
Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more things, but this is looking pretty good otherwise!

packages/remote-feature-flag-controller/package.json Outdated Show resolved Hide resolved
packages/remote-feature-flag-controller/src/logger.ts Outdated Show resolved Hide resolved
Comment on lines 7 to 10
export const incomingTransactionsLogger = createModuleLogger(
projectLogger,
'remote-feature-flag',
);
Copy link
Contributor

@mcmire mcmire Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I see that you copied this pattern from transaction-controller. It seems that they are putting all of their logger objects in this file. I guess that is okay — there isn't clear guidance on this. But should we at least name this variable and the scope appropriately?

Suggested change
export const incomingTransactionsLogger = createModuleLogger(
projectLogger,
'remote-feature-flag',
);
export const remoteFeatureFlagControllerLogger = createModuleLogger(
projectLogger,
'remote-feature-flag-controller',
);

As an alternative to this, you could put this variable at the top of remote-feature-flag-controller.ts itself and name it log, with the scope named after the class/function/file that's being logged. Here is another example to demonstrate this approach:

const log = createModuleLogger(projectLogger, 'etherscan');

And so you could have a similar one for remote-feature-flag-controller like so:

export const log = createModuleLogger(projectLogger, 'RemoteFeatureFlagController');

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your second suggestion has been applied here 440d170

// === STATE ===

export type RemoteFeatureFlagControllerState = {
remoteFeatureFlag: FeatureFlags;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that this was changed recently. Just want to double-check, should this be remoteFeatureFlags instead of remoteFeatureFlag, since there could be multiple?

Suggested change
remoteFeatureFlag: FeatureFlags;
remoteFeatureFlags: FeatureFlags;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 8f3c4d5

} catch (error) {
log('Remote feature flag API request failed: %o', error);
reject(error);
throw error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that we are returning the promise in the successful case but not the error case. So I see why you added this line. But since we have a promise that we are rejecting, it seems that we ought to be able to use it somehow for all cases...

What if instead of a try/catch we add this when we set up the promise above:

    const { promise, resolve, reject } = createDeferredPromise<FeatureFlags>({
      suppressUnhandledRejection: true,
    });
    this.#inProgressFlagUpdate = promise;
    promise.finally(() => {
      this.#inProgressFlagUpdate = undefined;
    });

And now we can put return await promise as the very last thing in this method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in 9454a8f


export const controllerName = 'RemoteFeatureFlagController';
export const DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 1 day
const log = createModuleLogger(projectLogger, 'ClientConfigApiService');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I just noticed this. Perhaps we don't need the additional logger in logger.ts? Maybe we just need projectLogger there, and we can correct the scope of this logger:

Suggested change
const log = createModuleLogger(projectLogger, 'ClientConfigApiService');
const log = createModuleLogger(projectLogger, 'RemoteFeatureFlagController');

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was addressed in 440d170

*
* @returns A promise that resolves to the current set of feature flags.
*/
async getRemoteFeatureFlag(): Promise<FeatureFlags> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to a previous comment, did we want to use getRemoteFeatureFlags since we're potentially grabbing multiple? Or is this fine? Just wanted to double-check the API is the way we want it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pluralized in 8f3c4d5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Needs more work from the author
Development

Successfully merging this pull request may close these issues.

5 participants