optimizely / react-sdk

React SDK for Optimizely Feature Experimentation and Optimizely Full Stack (legacy)
https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/javascript-react-sdk
Apache License 2.0
89 stars 36 forks source link

[BUG] High async storage usage #294

Open matinzd opened 4 days ago

matinzd commented 4 days ago

Is there an existing issue for this?

SDK Version

3.2.2

Current Behavior

High storage usage on AsyncStorage.

Expected Behavior

The storage should be flushed when old data is not needed anymore.

Steps To Reproduce

  1. Install optimizely SDK
  2. Release it to production with a error reporting tool
  3. You may see some users getting out of storage errors or hit limits for async storage manifest

React Framework

React Native

Browsers impacted

No response

Link

No response

Logs

Failed to write manifest file.Error Domain=NSCocoaErrorDomain Code=640 "You can’t save the file “manifest.json” because the volume “User” is out of space." UserInfo={NSURL=file:///var/mobile/Containers/Data/Application/...

Severity

Affecting users

Workaround/Solution

To follow up on https://github.com/optimizely/javascript-sdk/issues/952, it's better to move the storage implementation outside of the optimizely SDK so that we can use other solutions that have better performance and reliablity overall.

Recent Change

No response

Conflicts

No response

junaed-optimizely commented 4 days ago

Hey @matinzd , thanks for reporting this.

From the given log, it does seem like its an issue related to async storage and NSCocoaErrorDomain tells me its happening in IOS devices.

It might be due to any of the followings -

Its just hard to find the exact reason without more detail of the client. If you provide a little more specific information on how to reproduce that would be amazing for us to find out if there is any actual issue from our end.

When it comes to Optimizely SDK, we have working persistentCacheProvider in place. You can implement your own cache provider with following interface -

export default interface PersistentKeyValueCache<V = string> {

  contains(key: string): Promise<boolean>;

  get(key: string): Promise<V | undefined>;

  remove(key: string): Promise<boolean>;

  set(key: string, val: V): Promise<void>;

}

Then you have to pass the provider while instantiating -

const optimizely = createInstance({
   sdkKey: 'SDK_KEY',
   persistentCacheProvider: new CustomCacheProvider()
})

Its possible to switch from default async storage to storage of your choice in this way.

However, I have created an internal ticket FSSDK-10907 with a proposal to switch to a better default alternative than Async Storage.

matinzd commented 3 days ago

When it comes to Optimizely SDK, we have working persistentCacheProvider in place. You can implement your own cache provider with following interface -

Yeah I have done that but unfortunetaly even if I have my own storage implementation, I had to install async-storage because it's not being dynamically loaded in the optimizely core.

There are some parts of implementation that is still using async storage directly and that can cause issues.

However, I have created an internal ticket FSSDK-10907 with a proposal to switch to a better default alternative than Async Storage.

That would be great! Thank you so much :) I would suggest dynamically importing the default implementation would solve the issue.

It might be due to any of the followings -

I guess it can be a user problem but it's been more frequent for past couple of days that we have implemented optimizely. Given that manifest file does not have limitation, I would say that's a coincident for now and I can ignore it :) I also read about the cocoa error which is likely that user storage space is causing this.