> On Nov. 20, 2015, 10:12 p.m., Jie Yu wrote:
> > 3rdparty/libprocess/include/process/subprocess.hpp, lines 53-75
> > <https://reviews.apache.org/r/37336/diff/11/?file=1122402#file1122402line53>
> >
> >     What's the motivation of storing this? Should the caller already have 
> > those information?
> 
> Marco Massenzio wrote:
>     not necessarily - please note that this is executed asynchronously, so 
> the caller may have several of them running concurrently and having the 
> invocation returned together with the invocation will greatly simplifly the 
> caller's code.
>     
>     The whole point of this patch is to make the caller's API less 
> "low-level" and simplify the life of those using this facility.
>     
>     I have, for example, a module that executes commands upon an HTTP request 
> - having the `invocation` returned to me with the result, greatly simplifies 
> my code and enables me to return a Response without waiting for execution.
> 
> Jie Yu wrote:
>     From what I can tell from the code you pasted below, doesn't seem to 
> simplify the caller's code *a lot*.

Point well taken, but I'm confused here, Jie - on the one hand, you here seem 
to be unhappy it does not simplify enough, then below you suggest it simplifies 
too much.

The point here is - BenH and I went over the current usages of `subprocess()` 
and saw a common pattern, and agreed on a way that would enable us to (a) cover 
99% of usage patterns and (b) avoid the same boilerplate code to be repeated 
over and over again.

Three months on, and countless reviews after, this is what we arrived at: it 
would be good, at some point in time, to accept that this is **one** way of 
doing things, among countless others - and I'd like this code committed.

Unless we all agree that it's either buggy/flawed/wrong, in which case, I'm 
happy to discard this patch and re-start from scratch.


> On Nov. 20, 2015, 10:12 p.m., Jie Yu wrote:
> > 3rdparty/libprocess/include/process/subprocess.hpp, lines 119-130
> > <https://reviews.apache.org/r/37336/diff/11/?file=1122402#file1122402line119>
> >
> >     Why not just use a single `int status` field here. The users can use 
> > WEXITSTATUS ... to derive those information themself. This is also 
> > consistent with other places in the code place.
> 
> Marco Massenzio wrote:
>     `Subprocess` does exactly that (actually, it uses an `Option<int>`) - 
> this leaves the caller with the burned to do all the legwork: again and again 
> and again - it's all over the code base.
>     
>     The point of this patch is to encapsulate that work, having it done 
> (hopefully, properly) in **one** place and avoid to have the same code 
> sprinkled all over the codebase (and you can tell, most places, by copy & 
> paste).
> 
> Jie Yu wrote:
>     What if there's no returnCode (due to signal)? Should you use Option<int> 
> returnCode here? Similarly, should you use Option<int> for signal as well. 
> What will the client code be look like? Do you still need to check if 
> (returnCode.isSome()) ... if (signal.isSome()) ...
>     
>     Also
>     1) what if I want to know if WCOREDUMP is true or not, do you need to add 
> another boolean?
>     2) what if the reaper cannot reap the subprocess (i.e., we cannot get the 
> exit status)?

Please see the usage in the tests (this same patch).
`returnCode` is EXIT_FAILURE and `signal` is non-zero - in case one cares 
(which most folks don't seems to, but whatever).

if we can't get the exit status (`Subprocess::status` is `None()`) we return a 
`Failure` on the returned future and an error message (which is what ultimately 
is done practically everywhere `subprocess()` is used - while I guess I 
could've dreamt up tens of different scenarios, usage is pretty consistent in 
Mesos codebase and is what we're trying to encapsulate here).

Note that `Subprocess::status` is still available to callers.


> On Nov. 20, 2015, 10:12 p.m., Jie Yu wrote:
> > 3rdparty/libprocess/include/process/subprocess.hpp, line 328
> > <https://reviews.apache.org/r/37336/diff/11/?file=1122402#file1122402line328>
> >
> >     I don't like the name 'execute'. When you create the Subprocess 
> > instance, the subprocss is already launched and exec'ed. This is rather 
> > waiting for the subprocess to terminate.
> 
> Marco Massenzio wrote:
>     This method most definitely does **not** wait.
>     
>     This is how one can use it as a caller (code simplified):
>     ```
>       auto s = process::subprocess(commandInfo.command(), args);
>     
>       if (s.isError()) {
>         LOG(ERROR) << "Could not spawn subprocess: " << s.error();
>         return http::ServiceUnavailable(s.error());
>       }
>     
>       store(s.get().pid());  // <-- needed to reconcile with GETs
>     
>       Future<CommandResult> result_ = s->execute();
>       result_.then([](const Future<CommandResult> &future) {
>             if (future.isFailed()) {
>               // mark the command as failed
>               return Nothing();
>             }
>             auto result = future.get();
>             // update status of job - use pid(); something equivalent to:
>             LOG(INFO) << "Result of '" << result.invocation.command << "'was: 
> "
>                       << result.stdout();
>             return Nothing();
>           }).after(Seconds(30), [s](const Future<Nothing> &future) {
>             // update status of job to timed out; use `invocation` and 
> `stdout`.
>             s.get().cleanup();
>             return Nothing();
>           });
>     
>       http::Response response = http::OK("{\"result\": \"OK\", \"pid\": \"" +
>                                          stringify(s.get().pid()) + "\"}");
>       response.headers["Content-Type"] = "application/json";
>       return response;
>     ```
> 
> Jie Yu wrote:
>     From the code above, can you just caputure commandInfo.command() in the 
> lambda and print it?
>     
>     ```
>     string command = commandInfo.command();
>     
>     result_.then([command](...) {
>       ...
>       LOG(INFO) << command << "...";
>     });
>     ```
> 
> Jie Yu wrote:
>     ALso, `auto s = process::subprocess(commandInfo.command(), args);` this 
> line fork and exec the subprocess. So having another `s->execute()` sounds 
> very confusing to me.

I don't disagree - what would you suggest instead?

(note about the example above: it's contrived - one can also imagine storing 
the Future in a map keyed by the id, and retrieve the outcome upon receiving a 
GET requests on the pid status; there may be other scenarios where just passing 
the commandInfo and/or the args or whatever in the lambda may be less desirable 
 -- but, again, this is *one* way of doing things, not necessarily unique, and 
admittedly maybe not even *the* best).


> On Nov. 20, 2015, 10:12 p.m., Jie Yu wrote:
> > 3rdparty/libprocess/include/process/subprocess.hpp, lines 336-343
> > <https://reviews.apache.org/r/37336/diff/11/?file=1122402#file1122402line336>
> >
> >     Why introduce this method? I think the caller should be responsible for 
> > killing the subprocess if needed.
> >     
> >     Also, os::killtree is in general not reliable and shouldn't be used in 
> > library code.
> 
> Marco Massenzio wrote:
>     again, this is all about hiding implementation details from the caller 
> and make their life easier.
>     thanks for heads-up about `killtree()` - what would you suggest we use 
> instead?
>     
>     when you say "unreliable" what do you mean, exactly?
>     that it may fail to actually kill the process or that it risks blowing up 
> the app or segfaulting or whatever?
> 
> Jie Yu wrote:
>     I guess I don't understand in what scenario should you issue killtree?
>     
>     Why it's not reliable? What if a process reparents to init? What if a 
> process calls setsid to escape from a session?

well, I'd ratherr have something that works 99.9% of the cases in which it 
tries to clean up after itself, than nothing - obviously, if the process tries 
to do something clever to escape / avoid termination, I'm really not sure what 
else could one do about it?

Again - what is your alternative suggestion?

In the apidoc I was being rather explicit about the "no-guarantees" nature of 
this method:
```
the caller may want to try and clean up the process.
```
we give no refunds for failures to cleanup :)
(we can of course be even more explicit about the issues you mentioned).


- Marco


-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://reviews.apache.org/r/37336/#review107421
-----------------------------------------------------------


On Nov. 10, 2015, 8:51 p.m., Marco Massenzio wrote:
> 
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> https://reviews.apache.org/r/37336/
> -----------------------------------------------------------
> 
> (Updated Nov. 10, 2015, 8:51 p.m.)
> 
> 
> Review request for mesos, Joris Van Remoortere and Michael Park.
> 
> 
> Bugs: MESOS-3035
>     https://issues.apache.org/jira/browse/MESOS-3035
> 
> 
> Repository: mesos
> 
> 
> Description
> -------
> 
> The original API for `process::Subprocess` still left a lot of legwork
> to do for the caller; we have now added an `execute()` method
> that returns a `Future<Subprocess::Result>`.
>  
> `Subprocess::Result`, also introduced with this patch, contains useful 
> information
> about the command invocation (an `Invocation` struct); the exit code; 
> `stdout`;
> and, optionally, `stderr` too.
>  
> Once the Future completes, if successful, the caller will be able to retrieve
> stdout/stderr; whether the command was successful; and whether it received a 
> signal
> 
> 
> Diffs
> -----
> 
>   3rdparty/libprocess/include/process/subprocess.hpp 
> f17816e813d5efce1d3bb1ff1e1111850eeda3ba 
>   3rdparty/libprocess/src/subprocess.cpp 
> efe0018d0414c4137fd833c153eb262232e712bc 
>   3rdparty/libprocess/src/tests/subprocess_tests.cpp 
> ac600a551fb1a7782ff33cce204b7819497ef54a 
> 
> Diff: https://reviews.apache.org/r/37336/diff/
> 
> 
> Testing
> -------
> 
> make check
> 
> (also tested functionality with an anonymous module that exposes an 
> `/execute` endpoint and runs arbitrary commands, asynchronously,
> on an Agent)
> 
> 
> Thanks,
> 
> Marco Massenzio
> 
>

Reply via email to