Closed hifall closed 6 years ago
it should stay alive, no idea why it exits immediately. by the way, you shouldn’t call it manually. what editor are you using?
I am using MS Monaco. I need the R LS to stay up so that I can try to connect to it.
How can I view the log, so that I might find why it exits?
what happens if you run languageserver::run()
in R
If I run languageserver::run() in R's REPL, it looks like this:
> languageserver::run()
>
That is, it completes that command without printing anything.
How about languageserver::run(debug=T)
? Even Better, could you use debugOnce(languageserver::run)
to see which line does it jump out.
Here is what it produces:
> languageserver::run(debug=T)
connection type: stdio
exiting
> debugOnce(languageserver::run)
Error in debugOnce(languageserver::run) :
could not find function "debugOnce"
>
Do I need to install anything to use debugOnce? I am very new to R.
Sorry, I meant debugonce
. Nevermind, forget it for now.
How about the following? And what version of R are you using?
inputcon = file("stdin")
open(inputcon, blocking = FALSE)
isOpen(inputcon)
languageserver:::getppid()
My R:
R version 3.4.4 (2018-03-15) -- "Someone to Lean On" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit)
Running your commands yields:
> inputcon = file("stdin")
> open(inputcon, blocking = FALSE)
> isOpen(inputcon)
[1] TRUE
> languageserver:::getppid()
[1] 1
>
Oh I see, languageserver:::getppid()
is the reason. For some reasons, getppid
doesn't return the parent process id.
Glad you got it.
Now, is there anything I can do on my end to get around this issue, or do I have to wait for some fix in the future?
I actually don't have any clues how it could happen. getppid
should return the parent process id (unless it is an orphan process in which case it returns 1). But clearly you are running R on a shell and it is not an orphan.
On my Ubuntu machine,
> languageserver:::getppid()
[1] 6093
Weird. I am running this in Docker/Ubuntu 16.04. But I don't think that's the cause.
I have just fired up a rocker/tidyverse and it returns
> languageserver:::getppid()
[1] 156
>
docker run --name foobar -d rocker/tidyverse:3.4.4
docker exec -it foobar /bin/bash
# in the docker machine, open R and install languageserver
root@38a2dbc752d4:/# R
> install.packages("languageserver")
> languageserver:::getppid()
Interesting. I run this in a uber-complex container with tons of software packages installed, one of which is R. Therefore, R is not the only player here.
Although unlikely, but it's not entirely impossible caused by some external package configs.
I would have to remove these packages gradually in order to find out what is causing this issue, if at all.
There is much discussion on SO on why getppid returns 1, like these: https://stackoverflow.com/questions/15183427/getpid-and-getppid-return-two-different-values https://stackoverflow.com/questions/16078188/why-getppid-from-the-child-return-1
Not sure if these are relevant to the issue in discussion here.
Do you open R via a shell (e.g. Bash) at all?
Checking getppid
is important because it makes sure the R process will terminate itself. Some language servers don't check such and sometimes may leave a process running in the background after the editor is closed.
The way I run it:
Start the container:
docker run -it --entrypoint /bin/bash myimage
Then, run R in bash inside the container:
R
Then, enter:
languageserver:::getppid()
So yes, I do open R via a Bash.
how about check it using ps?
> ps -o pid,ppid,cmd | grep /usr/local/bin/R
539 289 grep /usr/local/bin/R
"Some language servers don't check such and sometimes may leave a process running in the background after the editor is closed."
As far as my experience with multiple language servers (LS) is concerned, a common pattern in their behavior is that if the editor disconnects, the LS becomes idle. And if an LS stays idle over some threshold (a couple minutes, a precise number doesn't matter here), it kills itself. So there will be no zombie process if the LS is designed like this.
root@851cf02ada5b:/# ps -o pid,ppid,cmd | grep /usr/local/bin/R
66 1 grep --color=auto /usr/local/bin/R
But still, checking the parent's state explicitly should be better than waiting for a couple minutes (sadly, not for your use case).
So it is not an issue of languageserver or R. There is something fishy on your system..
I might check the container later. Thanks for your help!
If you have new thoughts later, feel free to share:)
Okay, I trimmed down the Dockerfile to a minimal to create the image. Now it looks like:
FROM ubuntu:16.04
#Common deps
RUN apt-get update && apt-get -y install curl xz-utils vim unzip libssl-dev libreadline-dev zlib1g-dev
# Refer to: https://www.r-bloggers.com/how-to-install-r-ubuntu-16-04-xenial/.
RUN apt-get update && apt-get install -y libcurl4-openssl-dev && \
echo "deb http://cran.rstudio.com/bin/linux/ubuntu xenial/" | tee -a /etc/apt/sources.list && \
gpg --keyserver keyserver.ubuntu.com --recv-key E084DAB9 && \
gpg -a --export E084DAB9 | apt-key add - && \
apt-get update && \
apt-get install -y r-base r-base-dev && \
R --quiet --slave -e 'install.packages("languageserver")'
But still, running languageserver:::getppid()
gives:
> languageserver:::getppid()
[1] 1
>
So if indeed this getppid
thing is the issue, this issue can only come from the settings above, R, or the R language server, nothing else.
Thanks for the file, I will check it out later. 👍
I cannot reproduce with your Dockerfile....
docker build -t "randy3k:dockerfile" .
docker run --name foobar -dit randy3k:dockerfile
docker exec -it foobar /bin/bash
root@50277a9e326e:/# R
> languageserver:::getppid()
[1] 27
where 27 is the pid of bash
root@50277a9e326e:/# ps -o pid,ppid,cmd | grep bash
27 0 /bin/bash
51 27 grep --color=auto bash
This is getting more weird. The only remaining movable parts in the whole system I can think of are the OS and Docker.
My OS: Ubuntu 16.04 LTS. My Docker: 18.03.1-ce, build 9ee9f40.
Okay, there is actually one more thing: the way you run it is different than mine. I just executed your commands with complete fidelity and it seemed to give me a different result:
> languageserver:::getppid()
[1] 36
I ran it like below before, which is different than yours:
docker run -it --entrypoint /bin/bash myimage
R
> languageserver:::getppid()
[1] 1
>
Conclusion: the way I ran it causes getppid to always return 1.
That's interesting. I actually have never used the --entrypoint
argument.
check https://hackernoon.com/the-curious-case-of-pid-namespaces-1ce86b6bc900
It seems that you could start your container with --init
.
Thanks. Running with --init
does seem to keep the language server running from command line.
Hi @randy3k -- I'm running into this issue too, and I think that languageserver
refusing to run as a child of PID 1 is kind of a misfeature.
Consider the scenario of a language server client running in a Docker container as the Docker CMD
, so it's running as PID 1. As soon as the client tries to start up the R languageserver
the server exits immediately.
I've been integrating with a bunch of language servers lately and I've never encountered one before that behaves this way. IMO if an editor fails to clean up its child processes then that is a bug in the editor--it's not the job of the child process to try to detect this. Any chance this behavior could be changed?
IMO if an editor fails to clean up its child processes then that is a bug in the editor--it's not the job of the child process to try to detect this
I agree. However, I still think that it is beneficial to check if the process becomes an orphan. Provided that there is a workaround with the --init
option, I personally don't have much incentive to change the current behavior. With that said, I am open to any contribution allowing an option to control this behavior.
Hmm, let me try to persuade you that this is not beneficial but is instead bad non-standard behavior...
If you think about it, just about any Linux process could potentially be started by a parent process and then orphaned. But doing a check like this for PPID 1 is not standard practice in general, because the convention is that it's the parent's job to take care of cleaning up orphans.
This wouldn't be a big deal, except we live in a world where Docker is common and so running with PPID 1 is not unusual.
So all of a sudden, I can't wrap up a Docker app (say, an editor + an R language server) without completely changing my init system because this package is being "helpful." Yes, a workaround exists, but it adds a tiny amount of hassle to anyone who wants to use this package via Docker (i.e. if I want to distribute my Dockerized app then I have to remind the end user to pass --init
or else the language server will refuse to run).
In conclusion: non-standard behavior is bad, even when it's trying to be helpful, and the "right thing" would be to just remove the check. What do you think?
Perhaps we should disable the check specifically for docker? It seems that only docker users will want to disable it.
Well, that would be putting a hack on top of a hack, but it would be an improvement :). However, I don't think there exists a satisfactory way to test if you're inside a Docker container, as you can see from the long list of messy answers here.
Can I ask what editor you were using that was orphaning the process?
Thx for the info. I’ll take a look later. It is Sublime Text.
After I have installed successfully the R language server, I run the following command:
R --quiet --slave -e 'languageserver::run()'
This, I think, is supposed to start the language server. However, it exits in about 1 second without printing any message.
How do I start the language server and keep it alive and accepting input from stdin, like most other language servers do?
My env: Ubuntu 16.04.
Thanks!