-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
RPC ClientProxyHandler lazy init may lead to problems when proxies have dependencies on each other #13172
Comments
* add an event to listen for init events on rpc proxy handler * eager initialize DOCUMENTS_EXT Proxy when EDITORS_AND_DOCUMENTS_EXT was initialized
* add an event to listen for init events on rpc proxy handler * eager initialize DOCUMENTS_EXT Proxy when EDITORS_AND_DOCUMENTS_EXT was initialized
* automate init by specifying required remote depednencies on set
* add other dependencies * make sure to not start initialization multiple times
* add other dependencies * make sure to not start initialization multiple times
* add other dependencies * make sure to not start initialization multiple times
* add other dependencies * make sure to not start initialization multiple times
* add an event to listen for init events on rpc proxy handler * eager initialize DOCUMENTS_EXT Proxy when EDITORS_AND_DOCUMENTS_EXT was initialized
* automate init by specifying required remote depednencies on set
* add other dependencies * make sure to not start initialization multiple times
* don't throw error on possible race condition but log only
* don't throw error on possible race condition but log only
* don't throw error on possible race condition but log only * initialize dependencies before resolving promise
@jfaltermeier Very interesting problem indeed! I also had a quick look at it and at your proposed solution but I believe the problem runs a bit deeper. So very simplified the issue is that we send two related events (changing a file and closing a file) to two different proxies (Documents and EditorAndDocuments). While messages for a single proxy are ensured to arrive in the same order (since they are using the same channel and RpcProtocol), messages to two different proxies are using two different channels and there is no guarantee that the messages arrive in the same order. @tortmayr Do you maybe know if that is always the case? While in your case, the initialization of one of the proxies seems to create a delay that makes this problem very visible through the error, simply making the initialization faster will not fix the underlying issue and only ensure that it happens less likely. I see that in the Documents and EditorsAndDocuments case, we followed the same structure as VS Code (i.e. two proxies) even though they are reacting to related events. I'm not sure if the same problem can also occur in VS Code but to me it seems that the cleanest solution would be to sync the events/messages somehow. From the top of my head, I'd say the easiest solution is to only use a single proxy but I'm not sure how that impacts performance. |
* pause communication during init of handlers * introduce init callback allowing to implement this blocking mechanism
* rename from init callback to proxy synchronizer * use rpc promise to report init done
* rename from init callback to proxy synchronizer * use rpc promise to report init done
* rename from init callback to proxy synchronizer
Bug Description:
Currently this bug is visible as this error message on the browser console of the electron example application:
Steps to Reproduce:
yarn && yarn build && yarn download:plugins && yarn electron start
unknown document
exceptionAdditional Information
At the location where the error is thrown we have this code:
Here
DocumentsExtImpl
accesses information fromEditorsAndDocumentsExtImpl
(so we have a dependency between those two).The error chain is triggered like this (as far as I could see):
The
electron-menu-contribution
callsthis.preferenceService.set('window.titleBarStyle', this.titleBarStyle, PreferenceScope.User);
This will open
user-storage:/user/settings.json
, write to it, and close it again via thepreference-transaction-manager
. This is happening very fast.On the browser side
DocumentsMainImpl
andEditorsAndDocumentsMain
are both reacting to this and forward to their proxies in the expected order:EditorsAndDocumentsMain
callsthis.proxy.$acceptEditorsAndDocumentsDelta(deltaExt);
because there is a new document (
user-storage:/user/settings.json
).DocumentsMainImpl
callsthis.proxy.$acceptDirtyStateChanged(m.textEditorModel.uri, m.dirty);
because
user-storage:/user/settings.json
was touched.EditorsAndDocumentsMain
callsthis.proxy.$acceptEditorsAndDocumentsDelta(deltaExt);
again, because the document is closed again.
When we debug the other side of the communication (
DocumentsExtImpl
andEditorsAndDocumentsExtImpl
) we can see that$acceptDirtyStateChanged
arrives after the second$acceptEditorsAndDocumentsDelta
call, which leads to above error. The document is already removed fromeditorsAndDocuments
.I think the issue is that the
ClientProxyHandler
implementation has lazy initialization code:theia/packages/plugin-ext/src/common/proxy-handler.ts
Line 50 in 469bd74
While the
ClientProxyHandler
for editors-and-documents is already initialized (because it has been called before already) the documents handler is initialized on the firstacceptEditorsAndDocumentsDelta
call.This allows the second call to
acceptEditorsAndDocumentsDelta
to "overtake" the first one, leading to the exception.Hacking the
ClientProxyHandler
to callinitializeRpc()
in its constructor (i.e. basically removing the lazy init) removes the exception, but I guess this is not the desired solution.So I think we need a mechanism to sync the initialization of
ClientProxyHandler
s when they have dependencies on each other.This could e.g. be
I've played a bit with the listener mechanism and could open a PR if desired to kick off a discussion about the best solution.
The text was updated successfully, but these errors were encountered: