Skip to content

feat(base-data-service): Support persisting the cache - #9445

Merged
FrederikBolding merged 19 commits into
mainfrom
fb/base-data-service-persistence
Jul 15, 2026
Merged

feat(base-data-service): Support persisting the cache#9445
FrederikBolding merged 19 commits into
mainfrom
fb/base-data-service-persistence

Conversation

@FrederikBolding

@FrederikBolding FrederikBolding commented Jul 9, 2026

Copy link
Copy Markdown
Member

Explanation

Add support for cache persistence, which can be enabled by configuring persistenceConfig. Persistence is achieved using StorageService and debounced to not cause too many writes. Rehydration of the cache happens on init, while expired or invalid data is discarded. Any errors with persistence are logged, but ultimately ignored, due to the reduced importance of the data persisted.

This approach of storing the dehydrated state is similar to how @tanstack/query-persist-client-core works.

References

https://consensyssoftware.atlassian.net/browse/WPC-1128

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 communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
Touches shared data-layer caching and storage I/O; stale or rehydrated cache could affect offline/API behavior, though persistence is opt-in and errors are non-fatal.

Overview
Adds optional TanStack Query cache persistence to BaseDataService via a new constructor persistenceConfig (maxAge, optional writeDelay / maxWriteDelay). When enabled, successful query cache entries are dehydrated and written through messenger actions to @metamask/storage-service under key cache, with lodash debounced writes after cache add/update/remove and removeItem when the cache is empty.

Introduces init() to rehydrate from storage on startup; entries older than maxAge are dropped and removed. Persistence is off unless persistenceConfig is set; storage failures are swallowed (logged via captureException). destroy() now cancels pending debounced writes.

The package gains dependencies on @metamask/storage-service and lodash, exports PersistenceConfiguration, and includes broad persistence tests. README dependency graph and changelog are updated.

Reviewed by Cursor Bugbot for commit 79adfe5. Bugbot is set up for automated code reviews on this repo. Configure here.

@FrederikBolding
FrederikBolding force-pushed the fb/base-data-service-persistence branch from ceae8cf to 7412c82 Compare July 14, 2026 13:19
pull Bot pushed a commit to Reality2byte/core that referenced this pull request Jul 14, 2026
## Explanation

Separated out for review from
MetaMask#9445, since it is needed for
multiple PRs. Makes it easier to write tests for `BaseDataService` going
forward.

## References

N/A

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [ ] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them
(error) => this.#messenger.captureException?.(error),
);
},
this.#persistConfig.debounce ?? inMilliseconds(10, Duration.Second),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Open to suggestions for defaults here

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Seems fine. Could consider shortening to 5 seconds if this is too slow in practice. But even 10 seconds doesn't seem bad.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Since they are non-critical writes, my thinking was starting higher and tweaking later, but 🤷‍♂️

@FrederikBolding
FrederikBolding marked this pull request as ready for review July 15, 2026 09:07
@FrederikBolding
FrederikBolding requested a review from a team as a code owner July 15, 2026 09:07
Comment thread packages/base-data-service/src/BaseDataService.ts
this.#rehydrateCache().catch(
/* istanbul ignore next */
(error) => this.#messenger.captureException?.(error),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

init does not await rehydration

Medium Severity

init() starts #rehydrateCache but returns immediately without a Promise, so callers cannot await completion. Fetches issued right after init() may run before persisted data is hydrated and can hit the network even when valid cached data exists.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c12b77f. Configure here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think we want to wait for this anywhere, so this was intended 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why don't we want to wait?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I was thinking this would be similar to controllers providing a fire and forget init function to do setup.

I don't think we would want to block anywhere in the clients to wait for loading these persisted caches 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah I guess the question is, if cache persistence is not fully initialized will this prevent the data service from functioning correctly or would it cause adverse effects? It sounds like it would not, but just want to make sure.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It shouldn't, it just means that we may have to refetch queries. Similarly to if fetching the cache fails for whatever reason.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Okay, that's what I thought. Yeah I guess that's not so bad.

Comment thread packages/base-data-service/src/BaseDataService.ts Outdated
@FrederikBolding
FrederikBolding requested a review from Mrtenz July 15, 2026 09:30
Comment thread packages/base-data-service/tests/ExampleDataService.ts Outdated
Comment thread packages/base-data-service/src/BaseDataService.ts
@FrederikBolding
FrederikBolding requested a review from Mrtenz July 15, 2026 09:48
Comment thread packages/base-data-service/src/BaseDataService.ts
@FrederikBolding
FrederikBolding requested a review from Mrtenz July 15, 2026 11:28
Comment thread packages/base-data-service/src/BaseDataService.ts Outdated
Comment thread packages/base-data-service/src/BaseDataService.ts
Comment thread packages/base-data-service/src/BaseDataService.ts Outdated
this.#rehydrateCache().catch(
/* istanbul ignore next */
(error) => this.#messenger.captureException?.(error),
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why don't we want to wait?

Comment thread packages/base-data-service/src/BaseDataService.ts Outdated
Comment thread packages/base-data-service/src/BaseDataService.ts
Comment thread packages/base-data-service/src/BaseDataService.ts Outdated
Comment thread packages/base-data-service/src/BaseDataService.ts Outdated
Comment thread packages/base-data-service/CHANGELOG.md Outdated
Comment thread packages/base-data-service/src/BaseDataService.ts
@FrederikBolding
FrederikBolding force-pushed the fb/base-data-service-persistence branch from f0e55be to 43b812d Compare July 15, 2026 14:40
@FrederikBolding
FrederikBolding requested a review from mcmire July 15, 2026 14:40

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 43b812d. Configure here.

Comment thread packages/base-data-service/src/BaseDataService.ts
Comment thread packages/base-data-service/src/BaseDataService.ts
@FrederikBolding
FrederikBolding force-pushed the fb/base-data-service-persistence branch from 43b812d to 79adfe5 Compare July 15, 2026 14:54

@mcmire mcmire left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM!

@FrederikBolding
FrederikBolding added this pull request to the merge queue Jul 15, 2026
Merged via the queue into main with commit 146712f Jul 15, 2026
426 checks passed
@FrederikBolding
FrederikBolding deleted the fb/base-data-service-persistence branch July 15, 2026 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants