Multiple LanguageServers vs one JVM process [message #1790760] |
Fri, 15 June 2018 20:37 |
Daniel Lipski Messages: 20 Registered: May 2018 |
Junior Member |
|
|
Hi,
we are working on web application where users can write simple expressions via web forms. This application can be used simultaneously by few users. Application doesn't allow users to edit the same resource. We'be build web editor for our expression DSL with Monaco + LSP4J + XText.
When we started the project we didn't know too much about XText and LSP so we do it quite naively (?). When user opens the web page with expressions to edit (each expression is separate EMF resource) we start new LanguageServer. When user changes the script to edit we don't start new server, application changes the underlying resource. Code below is executed at the beginning of each user "session" (!= HttpSession), during this session user can edit many resources (one at a time):
LanguageServerImpl languageServer = injector.<LanguageServerImpl>getInstance(LanguageServerImpl.class);
Launcher<LanguageClient> launcher = LSPLauncher.createServerLauncher(languageServer,in,out);
languageServer.connect(launcher.getRemoteProxy());
launcher.startListening();
This works fine as long as we test it on a developer machine with just one concurrent user (only on language server is created at a time).
Now we are wondering if this approach will work with many concurrent users (test/prod environment)? All users have access to the same resources, but as I said application guards against concurrent modification of the same resource.
As far as I know XText today (still very poorly) XText(EMF?) uses static fields (registers) and is not designed to multithreaded environment ? if this is true how can we leverage power of XText in such architecture ? Do we have to lunch separate JVM process from our webapp for each "session" ? Or separate thread with dedicated classloader to "shield" one XTextServer from another ?
If my fears will be confirmed, "language server" as a name is a little confusing, because it suggests of multiuser support out-of-the-box (like ftp server, http server , chat server etc) :(
Daniel
|
|
|
|
|
|
|
Re: Multiple LanguageServers vs one JVM process [message #1790938 is a reply to message #1790767] |
Wed, 20 June 2018 11:41 |
Daniel Lipski Messages: 20 Registered: May 2018 |
Junior Member |
|
|
Hi,
we have another conceptual problem - we don't know if such functionality is provided by XText/LanguageServer or we should implement this by our own.
Below is simplified version of our scenario:
1)User opens web page with list of resources. Each of this resources is a script of our expression DSL stored in DB (or file on disk - its irrelevant for this discussion)
2)User chooses one of this resources and edit it via Monaco editor. Script edition is supported (error checking, validation etc) by LanguageServer/XText
3)User chooses another script (resource) to edit (content of this resource shuold be loaded to editor)
4)After editing one or few resources user clicks "save" and all changed resources are persisted.
So far we worked on step 2) - we created expression grammar, integrated XText + LSP4J + Monaco etc. (We don't have any persistence mechanism so each time user started with empty Monato editor. )
Now we start working on 1) , 3) and 4) and we don't know if LanguageServer/XText provides any support in this area ?
For example, if we(for test purpose only) created file on disk with our DSL and initialized Monaco with uri pointing to this file, content of this file was parsed by Xtext and LSP but not content was visible in an editor. (if DSL was incorrect monaco correctly displayed validation errors but without content).
Another problem, is of retriving text content of each XtextResource when user clicks save button. XText resources contains AST (EObjects) not text entered in Monaco.
I have feeling that we miss some basic knowledge about XText/EMF/LanguageServer and we don't know where to start. Another option is that we are trying to do something that Xtext/LSP is not supporting out of the box. What we tried so far is to "bind" XTexty resources "physical recources" (files, records is DB) via URIHandlers/Resources/ResourceFactories but none of this worked.
When I've read LSP specification (about didOpen message) I concluded that content of file being opened is send from Monacto to LSP not vice-versa. Am I right ? (Its opossite what we assumed)
Whats more, we found that in LSP4J code that didSave message is not implemented.
I also found this https://www.eclipse.org/Xtext/documentation/330_web_support.html#getting-text-content but Its not about LSP :(
That's why we suspect that tasks 1) 3) and 4) from above list should be implemented by our own.
Before we start working on them I wonted to be sure that we don't miss anything ?
[Updated on: Wed, 20 June 2018 11:50] Report message to a moderator
|
|
|
Re: Multiple LanguageServers vs one JVM process [message #1790959 is a reply to message #1790938] |
Wed, 20 June 2018 15:37 |
|
i dont think this is xtext specific.
as ls basically are designed to work with the same filesystem in client and backend for everything else you have to mimic that behaviour yourself.
its the same with other language servers.
=> during work the client sends changes to backend but appart from that the sharing of the files
has to happen over another channel (.e.g. using custom uri handling and processing for that uris)
=> saving is a client side thing
=> opening is a client side thing.
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
Re: Multiple LanguageServers vs one JVM process [message #1790962 is a reply to message #1790960] |
Wed, 20 June 2018 15:59 |
|
p.p.s:
in a single file scenario you might be able to mimic that by initializte from client with no uri and work with the open request only, but i dont know how well this is supported (have not tried it yet)
problematic with that is that all open files would go into one virtual project and see each other
=> will work only if
- you dont have refs between files
- you adapt scoping to ignore global scope
- you adapt the language servers "virtual project" handling
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
[Updated on: Wed, 20 June 2018 17:13] Report message to a moderator
|
|
|
Re: Multiple LanguageServers vs one JVM process [message #1790967 is a reply to message #1790962] |
Wed, 20 June 2018 16:28 |
|
did some experiments on that and at least in unit test it seems to work
languageServer.initialize(new InitializeParams => [])
val urix = 'inmemory:/foo/bar.testlang';
val model = '''type Foo { } xxxx'''
open(urix, model);
println(diagnostics.get(urix))
languageServer.didChange(new DidChangeTextDocumentParams => [
textDocument = new VersionedTextDocumentIdentifier => [
uri = urix
version = 2
]
contentChanges = #[
new TextDocumentContentChangeEvent => [
range = new Range(new Position(0, model.length - 5), new Position(0, model.length))
text = ""
]
]
])
println(diagnostics.get(urix))
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
Re: Multiple LanguageServers vs one JVM process [message #1790997 is a reply to message #1790967] |
Thu, 21 June 2018 08:39 |
Daniel Lipski Messages: 20 Registered: May 2018 |
Junior Member |
|
|
Ok, so you confirmed what I suspected (open/save it not LS responsibility).
Regarding code above, what is "diagnostics" object ? How to obtain/create it ? Where we can find same information about such classes and LS internals ?
In our case we have refs between resources, and scopeProvider must be aware of EObjects from different files.
If LS is not responsible for open/save and we have cross refs between I imagine such solution:
1)When LS starts we should add existing resources to resourceset - to be parsed by Xtext (EObjects will be in index and cross refs and scoping will work)
2)When user starts editing one of this resources we should load content of this file into Monaco editor
3)After editing few resources, when users saves all of (modified/unmodified) resources (in one operation) we should get text content of each resource and persist is (disk/db) by our own.
Few questions about this scenario
In step 2) when we have to load content to monaco - we should get text content of resource being edited, we cant load id from persistent storage because this resource may be dirty (user can edit the same resource few times before save and we should obtain latest, still transient version).
Is it possible to get text content of xtext resource ? Is it "diagnostics.get(urix)" for ? If few files where modified before save, does Xtext/LS keep content for each of them and this solution will work ? If a file was loaded by LS (step1) and not yet edited if it also work ?
If this sollution will not work, I imagine we will finish with 3 "states" of each resource:
a)persisted unparsed (db/files) - updated after users clicks "save all"
b)transient-parsed (resources managed by XText/LSP) - contains eobjects - loaded in step 1) and updated by LS
c)transient-unparsed (text content of each resource to be able to load it to editor) - we will have to update them by our own (they are independent of xtext resources)
What I worry about is that the same resource have two representations b) and c) and we have to write code to keep them synchronized (when user type something in a editor LS will update parsed state and our code should update unparsed state). Do you see better solution ? If we have to do this, we should somehow intercept didChange operation and after LS changes XTextResource (b) we should update (c), any idea how implement such "interception" ?
If there is a solution not keeping separate set of unparsed resources (c) how can we access all resources from LS ? I asked you in separate topic, and solution you provided worked, but in this scenario we don't have access to another resource from the same resourceset we can't call: resouce.getResourceSet().
Hope, you understand me.I I appreciate your help so far.
Daniel
|
|
|
Re: Multiple LanguageServers vs one JVM process [message #1791001 is a reply to message #1790997] |
Thu, 21 June 2018 09:35 |
|
have a look at the tests in xtext-core.
the diagostics objects collects the validation results based on the open/change requests.
thus it allows to simulate what happens.
the inizialize project gets and uri. its then part of the server side to do whatever is needed to initially parse the project
yoiu have to care about all syncing and proper handling yourself
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.05398 seconds