The process of creating client/languageClient objects when the extension initializes, or recovers from a crash, is not well managed/synchronized. There is a mixture of async code and sync code (that kicks off async code without waiting for it).
Currently, there is a bug where, if the process of recovering from a crash is interrupted with another crash (in the LSP initialization message) or a transient failure to execute the process, two crash recoveries will run simultaneously, resulting in multiple initializations of the same cpptools process.
Although we can move sync code out of constructors (for DefaultClient, etc.) and into async init functions fairly simply, so we can await stuff, that incurs possible deadlocks (perhaps in combination with the enqueue chain, which is client-specific), making this not a trivial fix.
Keeping this open to track cleaning up client creation logic. We've mitigated this on the native side, so this isn't critical, but there could be more going wrong here.
The process of creating client/languageClient objects when the extension initializes, or recovers from a crash, is not well managed/synchronized. There is a mixture of async code and sync code (that kicks off async code without waiting for it).
Currently, there is a bug where, if the process of recovering from a crash is interrupted with another crash (in the LSP initialization message) or a transient failure to execute the process, two crash recoveries will run simultaneously, resulting in multiple initializations of the same cpptools process.
Although we can move sync code out of constructors (for DefaultClient, etc.) and into async init functions fairly simply, so we can await stuff, that incurs possible deadlocks (perhaps in combination with the
enqueue
chain, which is client-specific), making this not a trivial fix.