fix: exception when executing multiple fetches of the same avatar [WPB-9640] #3101
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
PR Submission Checklist for internal contributors
The PR Title
SQPIT-764
The PR Description
What's new in this PR?
Issues
Sometimes there is a
FileNotFoundException
when fetching assets.Causes (Optional)
This exception happens when the app needs to fetch the same image multiple times - coil library (which the app uses to fetch, cache and show images) makes separate requests for each image composable and our logic for downloading image involves storing this image in the temporary cache file, so if we have 2 requests at the same time, one can edit or remove this file and then second can get this FileNotFoundException.
So this happens when for instance we have multiple messages from some user (there have to be minimum 2 avatars of that user on the screen, so not grouped messages) and this user changes avatar so the app needs to fetch and update these avatars. Sometimes, when at least two the same requests happen to be executed at the same time, this exception can occur, so not always, but it’s also visible on the screen because not all avatars of this user are visible, some of them are successful but others are broken because other request already removed a temporary file.
Solutions
The easiest solution would be to make different cache file names for each request so that each one has its own temporary file instead of having one temporary image per specific user avatar, but this way the app still makes multiple requests when only one is required.
Solution from this PR works by creating a mutex map, where a mutex is created and locked for a given key, so that multiple executions for a given key will never be executed at the same time but sequentially one by one. This is needed when the app needs to make a request to download updated avatar so that it won't make multiple requests unnecessary, but only the first execution which locks the mutex will make a request and store the avatar in a file and then other executions will run after that one by one so making another requests won't be needed anymore because the avatar is already available in a file. Also, when there is already avatar downloaded and stored in the file, then thanks to the mutex this file won't be accessed by multiple executions at the same time.
MutexMap
creates a mutex associated with a key and locks it so that there's only one execution going for a given key at a given time. When the lock for the given key is executed for the first time, it will create a new entry in the map and lock the mutex. When another lock is executed for the same key while it's locked, it will increase the count and lock the mutex so that it'll wait and execute after the first execution unlocks the mutex. The count is there to keep the mutex in the map as long as it's needed. After the last unlock, the mutex is removed from the map.Testing
How to Test
Attachments (Optional)
Attachments like images, videos, etc. (drag and drop in the text box)
fetch_avatar_multiple_times_issue.mp4
fetch_avatar_multiple_times_fix.mp4
User Michaltest546_2 changed the avatar, when opening his profile the app fetches new data of that user and realises that there is new avatar so after going back to conversation screen it tries to fetch this avatar, but there are 4 elements that should show this avatar so it wants to fetch it 4 times - on the video "before" it actually makes 4 requests at the same time, some of them are successful but others are broken because other request already removed a temporary file. On the video "after" it only makes one request and all other executions wait until it's fetched and can access it from the local file.
PR Post Submission Checklist for internal contributors (Optional)
PR Post Merge Checklist for internal contributors
References
feat(conversation-list): Sort conversations by most emojis in the title #SQPIT-764
.