Fix app hang when sending long comments - #8691
Conversation
fe65104 to
f4fca97
Compare
marcaaron
left a comment
There was a problem hiding this comment.
Just leaving a few thoughts.
| // For longer comments, skip parsing and display plaintext for performance reasons. It takes over 40s to parse a 100k long string!! | ||
| const parser = new ExpensiMark(); | ||
| const commentText = parser.replace(text); | ||
| const commentText = text.length < 10000 ? parser.replace(text) : text; |
There was a problem hiding this comment.
question: Does this mean we will not render markdown for these?
There was a problem hiding this comment.
10000 characters feels kind of magic. How did we land on this? Also what about a solution that accounts for the restrictions in Auth and this issue? e.g. could we chunk this into a few different messages so that it stays under the limit?
There was a problem hiding this comment.
question: Does this mean we will not render markdown for these?
Correct!
10000 characters feels kind of magic. How did we land on this? Also what about a solution that accounts for the restrictions in Auth and this issue? e.g. could we chunk this into a few different messages so that it stays under the limit?
10k came from the timing in my tests here, i.e. 10k took 600ms to parse vs 20k took 2.2s.
I tried chunking, i.e. calling addAction multiple times with chunks of 1k, 5k, 10k and 20k chars, but that didn't seem to have any effect on the performance. I think that the regex parsing is at least a O(n) operation, so breaking it down into chunks wouldn't matter when parsing n or m*n/m chars. Having said that, maybe I'm missing something in your suggestion?
There was a problem hiding this comment.
Did we perform those tests on a development or production build?
Should we expect this work to be relatively consistent from one machine to the next?
There was a problem hiding this comment.
Did we perform those tests on a development or production build?
That was on a development build.
Should we expect this work to be relatively consistent from one machine to the next?
The amount of work (number of operations) should be the same across machines, but the timing will vary. A prod build running on a mobile device would probably be the best benchmark to use, although I think it's more common for users to send large messages over web/desktop.
There was a problem hiding this comment.
So if we put in a large markdown comment it will work as text, but not get converted. That seems kind of broken, but also unsure if it's worth optimizing right now.
Having said that, maybe I'm missing something in your suggestion?
I see. So chunking didn't improve the performance? Where is the performance bottleneck exactly - in the JS thread? If we are having an issue with the performance of our markdown parser the first thoughts that come to mind are...
- Can we make the parser more efficient?
- If not, can we move the work the parser has to do onto a different thread (assuming our issue is that it's blocking the main JS)?
Separately, I took a look at the original issue which mentions stuff about how someone could "crash" another client by sending a message and unclear how it is related to parsing when we are adding a comment or how this change will fix that.
Anyways, just curious about this, thanks!
There was a problem hiding this comment.
So if we put in a large markdown comment it will work as text, but not get converted. That seems kind of broken, but also unsure if it's worth optimizing right now.
Agreed. With the current solution, we could limit the number of characters to 10k and not disable markdown.
So chunking didn't improve the performance?
I didn't see any improvements in performance.
Where is the performance bottleneck exactly - in the JS thread?
Correct!
Can we make the parser more efficient?
Probably and I considered it, but the more I looked into it the more of a rabbit hole it became 😅 specially considering this is a bit of an edge case. We could look at some external parsing library (assuming that it would be faster than ours).
If not, can we move the work the parser has to do onto a different thread (assuming our issue is that it's blocking the main JS)?
This looks like a possibility. It would stop blocking the JS thread, but wouldn't it still take a long time to parse the message?
Separately, I took a look at the original issue which mentions stuff about how someone could "crash" another client by sending a message and unclear how it is related to parsing when we are adding a comment or how this change will fix that.
Ah yea, but that assumed that sending such a large message to a user would succeed. Auth actually returns a 402 Maximum size exceeded error to that API call.
There was a problem hiding this comment.
This looks like a possibility. It would stop blocking the JS thread, but wouldn't it still take a long time to parse the message?
Yeah I'm not sure if this is a great idea or even possible, but at a high level it seems the user could at least do other things while the parsing happens.
Ah yea, but that assumed that sending such a large message to a user would succeed.
Ok got it. So that's not our problem then. And we have an issue with the markdown parser performance. Thanks!
Not necessarily against the idea to prevent large comments if there is no way to support them, but the parser will still be slow if we do this - so wondering if we need to look to improve the performance of the parsing in general or what exactly is happening there. I think it's not the first time I heard it was slow, but can't remember the exact context.
There was a problem hiding this comment.
Yea, I'm gonna look into improving the performance next 👍
There was a problem hiding this comment.
Ok, I created an issue to investigate our parser performance and the slow regex test - https://github.com/Expensify/Expensify/issues/208027.
Julesssss
left a comment
There was a problem hiding this comment.
I think this is a fine solution for now, the main problem is solved (you can crash any user client lol) and we can improve parser performance later on too.
|
Gonna merge this one and keep investigating the performance on this issue. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚀 Deployed to staging by @luacmartins in version: 1.1.57-0 🚀
|
|
🚀 Deployed to production by @chiragsalian in version: 1.1.57-17 🚀
|
|
Heyhey! We forgot to apply this behavior when editing comments! #15307 |

Details
cc @Julesssss
Fixed Issues
$ https://github.com/Expensify/Expensify/issues/205451
Tests
User is typing messageand the UI is not broken.You appear to be offlinemessage and the UI is not broken.PR Review Checklist
Contributor (PR Author) Checklist
### Fixed Issuessection aboveTestssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*filesSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)/** comment above it */displayNamepropertythisproperly so there are no scoping issues (i.e. foronClick={this.submit}the methodthis.submitshould be bound tothisin the constructor)thisare necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);ifthis.submitis never passed to a component event handler likeonClick)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)Avataris modified, I verified thatAvataris working as expected in all cases)PR Reviewer Checklist
### Fixed Issuessection aboveTestssectionQA stepssectiontoggleReportand notonIconClick).src/languages/*filesSTYLE.md) were followed/** comment above it */displayNamepropertythisproperly so there are no scoping issues (i.e. foronClick={this.submit}the methodthis.submitshould be bound tothisin the constructor)thisare necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);ifthis.submitis never passed to a component event handler likeonClick)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)Avataris modified, I verified thatAvataris working as expected in all cases)QA Steps
Same steps from the
Testssection.Screenshots
Web
web.mov
Mobile Web
mweb.mov
Desktop
desktop.mov
iOS
ios.mov
Android
android.mov