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

Fixed race condition on monaco editor initialization #8563

Merged

Conversation

federicobozzini
Copy link
Contributor

What it does

This PR fixes #8562. I think it was caused by a race condition in the Monaco Editor inizialization and this is one possible way to fix it.

How to test

To test try to run the browser version of Theia on windows, with a slow frontend contribution, and access Theia with a windows machine.

This fix prevents MonacoTextModelService to run until MonacoEditorProvider is properly initialized, preventing the issue from happening.

Review checklist

Reminder for reviewers

Copy link
Member

@vince-fugnitto vince-fugnitto left a comment

Choose a reason for hiding this comment

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

Thank you for the fix, there are build errors.

@federicobozzini federicobozzini force-pushed the monaco-race-condition branch 2 times, most recently from 45cc46e to ff354d6 Compare September 25, 2020 15:55
@federicobozzini
Copy link
Contributor Author

Thank you for the fix, there are build errors.

Thanks, I've fixed it. It seems there is still some issue with the dependencies but I don't think it's related to this PR.

@marcdumais-work
Copy link
Contributor

It seems there is still some issue with the dependencies but I don't think it's related to this PR.

Indeed - it's because of vscode-ripgrep and not related to the PR.

@paul-marechal
Copy link
Member

@federicobozzini For the sake of verification, could you provide us with some pseudo stack trace illustrating the race condition?

I'd like to understand the chain of events that lead to the issue, and I am having trouble finding it on my end.

@vince-fugnitto vince-fugnitto added the monaco issues related to monaco label Sep 28, 2020
@federicobozzini
Copy link
Contributor Author

federicobozzini commented Sep 28, 2020

The stacktrace of the files creation on the frontend side is:

Click to expand
(anonymous) (user-storage-service-filesystem.ts:96)
step (user-storage-service-filesystem.ts:15)
(anonymous) (user-storage-service-filesystem.ts:15)
fulfilled (user-storage-service-filesystem.ts:15)
Promise.then (async)
step (user-storage-service-filesystem.ts:15)
fulfilled (user-storage-service-filesystem.ts:15)
Promise.then (async)
step (user-storage-service-filesystem.ts:15)
(anonymous) (user-storage-service-filesystem.ts:15)
push.../../node_modules/@theia/userstorage/lib/browser/user-storage-service-filesystem.js.__awaiter (user-storage-service-filesystem.ts:15)
push.../../node_modules/@theia/userstorage/lib/browser/user-storage-service-filesystem.js.UserStorageServiceFilesystemImpl.saveContents (user-storage-service-filesystem.ts:87)
push.../../node_modules/@theia/userstorage/lib/browser/user-storage-resource.js.UserStorageResource.saveContents (user-storage-resource.ts:51)
(anonymous) (resource.ts:98)
step (resource.ts:15)
(anonymous) (resource.ts:15)
fulfilled (resource.ts:15)
Promise.then (async)
step (resource.ts:15)
(anonymous) (resource.ts:15)
../../theia/packages/core/lib/common/resource.js.__awaiter (resource.ts:15)
save (resource.ts:88)
(anonymous) (monaco-editor-model.js:520)
step (monaco-editor-model.js:59)
(anonymous) (monaco-editor-model.js:40)
fulfilled (monaco-editor-model.js:31)
Promise.then (async)
step (monaco-editor-model.js:33)
(anonymous) (monaco-editor-model.js:34)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.__awaiter (monaco-editor-model.js:30)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.MonacoEditorModel.doSave (monaco-editor-model.js:496)
(anonymous) (monaco-editor-model.js:452)
(anonymous) (monaco-editor-model.js:339)
step (monaco-editor-model.js:59)
(anonymous) (monaco-editor-model.js:40)
(anonymous) (monaco-editor-model.js:34)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.__awaiter (monaco-editor-model.js:30)
(anonymous) (monaco-editor-model.js:333)
Promise.then (async)
(anonymous) (monaco-editor-model.js:333)
step (monaco-editor-model.js:59)
(anonymous) (monaco-editor-model.js:40)
(anonymous) (monaco-editor-model.js:34)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.__awaiter (monaco-editor-model.js:30)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.MonacoEditorModel.run (monaco-editor-model.js:327)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.MonacoEditorModel.scheduleSave (monaco-editor-model.js:452)
(anonymous) (monaco-editor-model.js:437)
setTimeout (async)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.MonacoEditorModel.doAutoSave (monaco-editor-model.js:436)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.MonacoEditorModel.markAsDirty (monaco-editor-model.js:429)
push.../../node_modules/@theia/monaco/lib/browser/monaco-editor-model.js.MonacoEditorModel.fireDidChangeContent (monaco-editor-model.js:465)
(anonymous) (monaco-editor-model.js:179)
(anonymous) (textModel.ts:237)
Emitter.fire (event.ts:581)
DidChangeContentEmitter.fire (textModel.ts:3100)
TextModel._emitContentChangedEvent (textModel.ts:374)
TextModel.setEOL (textModel.ts:461)
ModelServiceImpl._setModelOptionsForModel (modelServiceImpl.ts:230)
ModelServiceImpl._updateModelOptions (modelServiceImpl.ts:224)
(anonymous) (modelServiceImpl.ts:131)
Emitter.fire (event.ts:581)
(anonymous) (monaco-frontend-module.ts:179)
(anonymous) (event.ts:117)
../../theia/packages/core/lib/common/event.js.CallbackList.invoke (event.ts:125)
../../theia/packages/core/lib/common/event.js.Emitter.fire (event.ts:267)
push.../../node_modules/@theia/monaco/lib/browser/monaco-configurations.js.MonacoConfigurations.reconcileData (monaco-configurations.ts:48)
(anonymous) (monaco-configurations.ts:44)
(anonymous) (event.ts:117)
../../theia/packages/core/lib/common/event.js.CallbackList.invoke (event.ts:125)
../../theia/packages/core/lib/common/event.js.Emitter.fire (event.ts:267)
../../theia/packages/core/lib/browser/preferences/preference-service.js.PreferenceServiceImpl.reconcilePreferences (preference-service.ts:206)
(anonymous) (preference-service.ts:128)
(anonymous) (event.ts:117)
../../theia/packages/core/lib/common/event.js.CallbackList.invoke (event.ts:125)
../../theia/packages/core/lib/common/event.js.Emitter.fire (event.ts:267)
(anonymous) (preference-provider.ts:115)
(anonymous) (index.js:21)
setTimeout (async)
(anonymous) (index.js:18)
(anonymous) (index.js:13)
../../theia/packages/core/lib/browser/preferences/preference-provider.js.PreferenceProvider.emitPreferencesChangedEvent (preference-provider.ts:90)
../../theia/packages/core/lib/browser/preferences/preference-contribution.js.PreferenceSchemaProvider.setSchema (preference-contribution.ts:258)
push.../../node_modules/@theia/languages/lib/browser/languages-frontend-contribution.js.LanguagesFrontendContribution.onStart (languages-frontend-contribution.ts:54)
(anonymous) (frontend-application.ts:346)
(anonymous) (frontend-application.ts:376)
step (frontend-application.ts:15)
(anonymous) (frontend-application.ts:15)
(anonymous) (frontend-application.ts:15)
../../theia/packages/core/lib/browser/frontend-application.js.__awaiter (frontend-application.ts:15)
../../theia/packages/core/lib/browser/frontend-application.js.FrontendApplication.measure (frontend-application.ts:372)
(anonymous) (frontend-application.ts:345)
step (frontend-application.ts:15)
(anonymous) (frontend-application.ts:15)
step (frontend-application.ts:15)
(anonymous) (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)
Promise.then (async)
step (frontend-application.ts:15)
fulfilled (frontend-application.ts:15)

This is not too easy to debug because as far as I understand most of this process is not started explicitly but by a chain of object creations and inizialitazions managed by inversify.

The source of this error seems to come from the fact that the MonacoEditorProvider redefines the default EOL for the new resource models but if this initialization happens too late (because of a slow frontend contribution), when the resource models are initialized the incorrect default 'EOL` is used and this mismatch causes the files to get created (as if the file had changed).

@paul-marechal
Copy link
Member

I think I get a general sense of the issue thanks to your explanation.

I don't like this lock (deferred) to be exposed and waiting for some other component to release. It works, but I was looking for a different way to address the issue:

Is it possible to move the code on which the MonacoTextModelService depends upon into its own postConstruct method?

@federicobozzini
Copy link
Contributor Author

@marechal-p I agree with you. I've changed the code to move the EOL overriding to the MonacoTextModelService as you suggest.

Copy link
Member

@paul-marechal paul-marechal left a comment

Choose a reason for hiding this comment

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

LGTM.

@akosyakov you have more experience with the monaco integration, are we missing anything?

Copy link
Member

@paul-marechal paul-marechal left a comment

Choose a reason for hiding this comment

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

Took a second look and had a few remarks.

@paul-marechal paul-marechal force-pushed the monaco-race-condition branch from 9bb2437 to b3ca800 Compare October 6, 2020 16:09
paul-marechal
paul-marechal previously approved these changes Oct 6, 2020
Copy link
Member

@paul-marechal paul-marechal left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for the fix!

@paul-marechal paul-marechal dismissed their stale review October 6, 2020 17:50

Waiting for feedback.

@federicobozzini
Copy link
Contributor Author

@marechal-p I've done some investigation and the problem with plugins doesn't seem to happen anymore. This PR should be now safe to merge.

@paul-marechal
Copy link
Member

Please squash your commits, we can merge multi-commit PRs but the history has to stay clean from merge commits :)

@federicobozzini
Copy link
Contributor Author

@marechal-p It should now be ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
monaco issues related to monaco
Projects
None yet
4 participants