-
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
Make process creation asynchronous, improve error reporting #3447
Conversation
The error reporting when spawning a process fails (notably ENOENT and EACCES) is not very good currently. For example, after trying to execute a non-executable file, we get a RawProcess object with the `process` property undefined. When we try to execute a non-existent file, we get a RawProcess.process with an undefined pid. I think it's not very practical to be able to receive RawProcess objects that represent processes that we failed to start. With this patch, I propose to extract the actual process spawn from the RawProcess and TerminalProcess constructors and move that in some factory methods that return Promises. The RawProcess and TerminalProcess objects will be created to wrap successfully started processes. Errors will be propagated by returning rejected Promises. Doing this change has quite a bit of impact on other modules, but I think that in the end it's an API that's harder to misuse. Change-Id: I76bc0cc5ab0664c04ddc73e4d68e78948780f9d0 Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
The main driver for this patch is actually that I want to get rid of this |
It looks like a breaking change for all external extensions contributing language servers. //cc @svenefftinge |
@simark Can you elaborate why is it difficult to know? As I can see As an alternative, we could create a utility on the top of existing APIs to promisify the process creation without breaking everything. |
A concrete example is the requirement for tasks. We need to know at some point if the process has been started properly, so we can show a "Task X started" message. Otherwise, we need to know if there has been an error (as well as what is the error) so we can show a "Task X failed to start (reason XYZ)" message. It's easy to know when there is an error - you just listen for the event. But how do you know if/when the process has been successfully started?
Perhaps. |
I'm thinking we could add a
I wonder which one is better:
|
} | ||
|
||
get pid() { | ||
return this.process.pid; | ||
} | ||
|
||
get stdin() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have renamed input to stdin, output to stdout, errorOutput to stderr. It is not a necessary change, so I can revert that to reduce the number of breaking changes.
Which code? The whole code in repo does not check pid and works perfectly. For the task extension, you can check |
It works, but I wouldn't say it works perfectly. It doesn't handle EACCES problems correctly.
That makes it a pretty bad API, that's easy to mis-use. I would like if we made the situation better so that it's not possible for anybody else to fall in the same trap in the future. The |
That is indeed a massively breaking change. We could document the |
Yes, I agree. It depends what we mean by "successfully spawn" the process. If you pass wrong flags to your process and it exits right away, I consider that it has been successfully spawn (there has been a process spawned, which has then exited). Even in the case of missing shared library (at least on Linux), the process is successfully spawned, it just happens to fail during execution of userspace code. But there was a process spawn, it had a valid pid and everything, it just exited rather quickly.
That would be enough for the ENOENT case, but not the EACCES case. In the EACCES case, the https://github.com/theia-ide/theia/blob/master/packages/process/src/node/raw-process.ts#L54 so we can't even check for
but even that would be an API break. To fix my use case (the tasks) with the minimal, I am thinking of implemented what I suggested earlier, which is to add a |
@simark Could you open a PR without breaking changes? |
Yes, eventually. |
@simark I'm closing the pull-request for the moment because:
I understand you are quite busy but if you ever get the chance to find the time to re-work the pull-request feel free to re-open it 👍 |
The error reporting when spawning a process fails (notably ENOENT and
EACCES) is not very good currently.
For example, after trying to execute a non-executable file, we get a
RawProcess object with the
process
property undefined. When we try toexecute a non-existent file, we get a RawProcess.process with an
undefined pid. I think it's not very practical to be able to receive
RawProcess objects that represent processes that we failed to start.
With this patch, I propose to extract the actual process spawn from the
RawProcess and TerminalProcess constructors and move that in some
factory methods that return Promises. The RawProcess and
TerminalProcess objects will be created to wrap successfully started
processes. Errors will be propagated by returning rejected Promises.
Doing this change has quite a bit of impact on other modules, but I
think that in the end it's an API that's harder to misuse.
Change-Id: I76bc0cc5ab0664c04ddc73e4d68e78948780f9d0
Signed-off-by: Simon Marchi simon.marchi@ericsson.com