Page MenuHomePhorge

final class ExecFuture
Arcanist Technical Documentation ()

Execute system commands in parallel using futures.

ExecFuture is a future, which means it runs asynchronously and represents a value which may not exist yet. See Using Futures for an explanation of futures. When an ExecFuture resolves, it returns the exit code, stdout and stderr of the process it executed.

ExecFuture is the core command execution implementation in libphutil, but is exposed through a number of APIs. See Command Execution for more discussion about executing system commands.

Tasks

Configuring Execution

  • final public function setEnv($env, $wipe_process_env) — Set environmental variables for the command.
  • final public function updateEnv($key, $value) — Set the value of a specific environmental variable for this command.
  • final public function hasEnv() — Returns `true` if this command has a configured environment.
  • final public function getEnv() — Get the configured environment.
  • final public function setCWD($cwd) — Set the current working directory for the subprocess (that is, set where the subprocess will execute). If not set, the default value is the parent's current working directory.
  • final public function getCWD() — Get the command's current working directory.
  • public function setStdoutSizeLimit($limit) — Set a maximum size for the stdout read buffer. To limit stderr, see @{method:setStderrSizeLimit}. The major use of these methods is to use less memory if you are running a command which sometimes produces huge volumes of output that you don't really care about.
  • public function setStderrSizeLimit($limit) — Set a maximum size for the stderr read buffer. See @{method:setStdoutSizeLimit} for discussion.
  • public function setTimeout($seconds) — Set a hard limit on execution time. If the command runs longer, it will be terminated and the future will resolve with an error code. You can test if a future was killed by a timeout with @{method:getWasKilledByTimeout}.

Creating ExecFutures

No methods for this task.

Resolving Execution

  • public function resolvex(...) — Resolve a command you expect to exit with return code 0. Works like @{method:resolve}, but throws if $err is nonempty. Returns only $stdout and $stderr. See also @{function:execx}.
  • public function resolveJSON(...) — Resolve a command you expect to return valid JSON. Works like @{method:resolvex}, but also throws if stderr is nonempty, or stdout is not valid JSON. Returns a PHP array, decoded from the JSON command output.
  • public function resolveKill() — Resolve the process by abruptly terminating it.

Command Information

  • public function getStderrSizeLimit() — Retrieve the byte limit for the stderr buffer.
  • public function getStdoutSizeLimit() — Retrieve the byte limit for the stdout buffer.
  • public function getPID() — Get the process's pid. This only works after execution is initiated, e.g. by a call to start().

Interacting With Commands

  • public function read() — Read and return output from stdout and stderr, if any is available. This method keeps a read cursor on each stream, but the entire streams are still returned when the future resolves. You can call read() again after resolving the future to retrieve only the parts of the streams you did not previously read:
  • public function write($data, $keep_pipe) — Write data to stdin of the command.
  • public function discardBuffers() — Permanently discard the stdout and stderr buffers and reset the read cursors. This is basically useful only if you are streaming a large amount of data from some process.

Internals

  • public function isReady() — Begin or continue command execution.
  • public function getReadSockets() — Provides read sockets to the future core.
  • public function getWriteSockets() — Provides write sockets to the future core.
  • public function isReadBufferEmpty() — Determine if the read buffer is empty.
  • public function isWriteBufferEmpty() — Determine if the write buffer is empty.
  • public function getWriteBufferSize() — Determine the number of bytes in the write buffer.
  • private function readAndDiscard($stream, $limit, $description, $length) — Reads some bytes from a stream, discarding output once a certain amount has been accumulated.
  • public function __destruct()
  • private function closeProcess() — Close and free resources if necessary.
  • private function procGetStatus() — Execute `proc_get_status()`, but avoid pitfalls.
  • private function tryToCloseStdin() — Try to close stdin, if we're done using it. This keeps us from hanging if the process on the other end of the pipe is waiting for EOF.

Other Methods

Methods

public function __get($name)
Inherited

This method is not documented.
Parameters
$name
Return
wild

public function __set($name, $value)
Inherited

This method is not documented.
Parameters
$name
$value
Return
wild

public function current()
Inherited

This method is not documented.
Return
wild

public function key()
Inherited

This method is not documented.
Return
wild

public function next()
Inherited

This method is not documented.
Return
wild

public function rewind()
Inherited

This method is not documented.
Return
wild

public function valid()
Inherited

This method is not documented.
Return
wild

private function throwOnAttemptedIteration()
Inherited

This method is not documented.
Return
wild

public function getPhobjectClassConstant($key, $byte_limit)
Inherited

Phobject

Read the value of a class constant.

This is the same as just typing self::CONSTANTNAME, but throws a more useful message if the constant is not defined and allows the constant to be limited to a maximum length.

Parameters
string$keyName of the constant.
int|null$byte_limitMaximum number of bytes permitted in the value.
Return
stringValue of the constant.

public function isReady()

Future

Is this future's process complete? Specifically, can this future be resolved without blocking?

ExecFuture

Begin or continue command execution.

Return
boolTrue if future has resolved.

public function resolve()
Inherited

Future

Resolve a future and return its result, blocking until the result is ready if necessary.

Return
wildFuture result.

final public function updateFuture()
Inherited

This method is not documented.
Return
wild

private function startServiceProfiler()
Inherited

This method is not documented.
Return
wild

private function endServiceProfiler()
Inherited

This method is not documented.
Return
wild
This method is not documented.
Return
wild
This method is not documented.
Return
wild

public function getReadSockets()

Future

Retrieve a list of sockets which we can wait to become readable while a future is resolving. If your future has sockets which can be select()ed, return them here (or in getWriteSockets()) to make the resolve loop do a select(). If you do not return sockets in either case, you'll get a busy wait.

ExecFuture

Provides read sockets to the future core.

Return
listList of read sockets.

public function getWriteSockets()

Future

Retrieve a list of sockets which we can wait to become writable while a future is resolving. See getReadSockets().

ExecFuture

Provides write sockets to the future core.

Return
listList of write sockets.

public function getDefaultWait()

Future

Default amount of time to wait on stream select for this future. Normally 1 second is fine, but if the future has a timeout sooner than that it should return the amount of time left before the timeout.

ExecFuture
This method is not documented.
Return
wild

public function start()
Inherited

This method is not documented.
Return
wild

final protected function getResult()
Inherited

Future

Retrieve the final result of the future.

Return
wildFinal resolution of this future.

final protected function setResult($result)
Inherited

This method is not documented.
Parameters
$result
Return
wild

final public function hasResult()
Inherited

This method is not documented.
Return
wild

private function setException($exception)
Inherited

This method is not documented.
Parameters
$exception
Return
wild

private function getException()
Inherited

This method is not documented.
Return
wild

final public function hasException()
Inherited

This method is not documented.
Return
wild

final public function setFutureKey($key)
Inherited

This method is not documented.
Parameters
$key
Return
wild

final public function getFutureKey()
Inherited

This method is not documented.
Return
wild

final public function setRaiseExceptionOnStart($raise)
Inherited

This method is not documented.
Parameters
$raise
Return
wild

final public function getHasFutureStarted()
Inherited

This method is not documented.
Return
wild

final public function canResolve()
Inherited

This method is not documented.
Return
wild

private function endFuture()
Inherited

This method is not documented.
Return
wild

final public function __construct($pattern)
Inherited

This method is not documented.
Parameters
$pattern
Return
this//Implicit.//

protected function didConstruct()

This method is not documented.
Return
wild

final public function setResolveOnError($resolve_on_error)
Inherited

This method is not documented.
Parameters
$resolve_on_error
Return
wild

final public function getResolveOnError()
Inherited

This method is not documented.
Return
wild

final public function getCommand()
Inherited

This method is not documented.
Return
wild

final public function setEnv($env, $wipe_process_env)
Inherited

PhutilExecutableFuture

Set environmental variables for the command.

By default, variables are added to the environment of this process. You can optionally wipe the environment and pass only the specified values.

// Env will have "X" and current env ("PATH", etc.)
$exec->setEnv(array('X' => 'y'));

// Env will have ONLY "X".
$exec->setEnv(array('X' => 'y'), $wipe_process_env = true);
Parameters
map<string,$envstring> Dictionary of environmental variables.
bool$wipe_process_envOptionally, pass `true` to replace the existing environment.
Return
this

final public function updateEnv($key, $value)
Inherited

PhutilExecutableFuture

Set the value of a specific environmental variable for this command.

Parameters
string$keyEnvironmental variable name.
string|null$valueNew value, or null to remove this variable.
Return
this

final public function hasEnv()
Inherited

PhutilExecutableFuture

Returns true if this command has a configured environment.

Return
boolTrue if this command has an environment.

final public function getEnv()
Inherited

PhutilExecutableFuture

Get the configured environment.

Return
map<string, string>Effective environment for this command.

final public function setCWD($cwd)
Inherited

PhutilExecutableFuture

Set the current working directory for the subprocess (that is, set where the subprocess will execute). If not set, the default value is the parent's current working directory.

Parameters
string$cwdDirectory to execute the subprocess in.
Return
this

final public function getCWD()
Inherited

PhutilExecutableFuture

Get the command's current working directory.

Return
stringWorking directory.

public function getStderrSizeLimit()

Retrieve the byte limit for the stderr buffer.

Return
intMaximum buffer size, in bytes.

public function getStdoutSizeLimit()

Retrieve the byte limit for the stdout buffer.

Return
intMaximum buffer size, in bytes.

public function getPID()

Get the process's pid. This only works after execution is initiated, e.g. by a call to start().

Return
intProcess ID of the executing process.

public function hasPID()

This method is not documented.
Return
wild

public function setStdoutSizeLimit($limit)

Set a maximum size for the stdout read buffer. To limit stderr, see setStderrSizeLimit(). The major use of these methods is to use less memory if you are running a command which sometimes produces huge volumes of output that you don't really care about.

NOTE: Setting this to 0 means "no buffer", not "unlimited buffer".
Parameters
int$limitMaximum size of the stdout read buffer.
Return
this

public function setStderrSizeLimit($limit)

Set a maximum size for the stderr read buffer. See setStdoutSizeLimit() for discussion.

Parameters
int$limitMaximum size of the stderr read buffer.
Return
this

public function setReadBufferSize($read_buffer_size)

Set the maximum internal read buffer size this future. The future will block reads once the internal stdout or stderr buffer exceeds this size.

NOTE: If you resolve() a future with a read buffer limit, you may block forever!

TODO: We should probably release the read buffer limit during resolve(), or otherwise detect this. For now, be careful.

Parameters
int|null$read_buffer_sizeMaximum buffer size, or `null` for unlimited.
Return
this

public function read()

Read and return output from stdout and stderr, if any is available. This method keeps a read cursor on each stream, but the entire streams are still returned when the future resolves. You can call read() again after resolving the future to retrieve only the parts of the streams you did not previously read:

$future = new ExecFuture('...');
// ...
list($stdout) = $future->read(); // Returns output so far
list($stdout) = $future->read(); // Returns new output since first call
// ...
list($stdout) = $future->resolvex(); // Returns ALL output
list($stdout) = $future->read(); // Returns unread output
NOTE: If you set a limit with setStdoutSizeLimit() or setStderrSizeLimit(), this method will not be able to read data past the limit.
NOTE: If you call discardBuffers(), all the stdout/stderr data will be thrown away and the cursors will be reset.
Return
pair<$stdout, $stderr> pair with new output since the last call to this method.

public function readStdout()

This method is not documented.
Return
wild

public function write($data, $keep_pipe)

Write data to stdin of the command.

Parameters
string$dataData to write.
bool$keep_pipeIf true, keep the pipe open for writing. By default, the pipe will be closed as soon as possible so that commands which listen for EOF will execute. If you want to keep the pipe open past the start of command execution, do an empty write with `$keep_pipe = true` first.
Return
this

public function discardBuffers()

Permanently discard the stdout and stderr buffers and reset the read cursors. This is basically useful only if you are streaming a large amount of data from some process.

Conceivably you might also need to do this if you're writing a client using ExecFuture and netcat, but you probably should not do that.

NOTE: This completely discards the data. It won't be available when the future resolves. This is almost certainly only useful if you need the buffer memory for some reason.
Return
this

public function discardStdoutBuffer()

This method is not documented.
Return
wild

public function getWasKilledByTimeout()

Returns true if this future was killed by a timeout configured with setTimeout().

Return
boolTrue if the future was killed for exceeding its time limit.

public function setTimeout($seconds)

Set a hard limit on execution time. If the command runs longer, it will be terminated and the future will resolve with an error code. You can test if a future was killed by a timeout with getWasKilledByTimeout().

The subprocess will be sent a TERM signal, and then a KILL signal a short while later if it fails to exit.

Parameters
int$secondsMaximum number of seconds this command may execute for before it is signaled.
Return
this

public function resolvex(...)

Resolve a command you expect to exit with return code 0. Works like resolve(), but throws if $err is nonempty. Returns only $stdout and $stderr. See also execx().

list($stdout, $stderr) = $future->resolvex();
Parameters
floatOptional timeout after which resolution will pause and execution will return to the caller.
Return
pair<$stdout, $stderr> pair.

public function resolveJSON(...)

Resolve a command you expect to return valid JSON. Works like resolvex(), but also throws if stderr is nonempty, or stdout is not valid JSON. Returns a PHP array, decoded from the JSON command output.

Parameters
floatOptional timeout after which resolution will pause and execution will return to the caller.
Return
arrayPHP array, decoded from JSON command output.

public function resolveKill()

Resolve the process by abruptly terminating it.

Return
listList of <err, stdout, stderr> results.

private function recordResult($result)

This method is not documented.
Parameters
array$result
Return
wild

private function raiseResultError($result)

This method is not documented.
Parameters
$result
Return
wild

public function isReadBufferEmpty()

Determine if the read buffer is empty.

Return
boolTrue if the read buffer is empty.

public function isWriteBufferEmpty()

Determine if the write buffer is empty.

Return
boolTrue if the write buffer is empty.

public function getWriteBufferSize()

Determine the number of bytes in the write buffer.

Return
intNumber of bytes in the write buffer.

private function readAndDiscard($stream, $limit, $description, $length)

Reads some bytes from a stream, discarding output once a certain amount has been accumulated.

Parameters
resource$streamStream to read from.
int$limitMaximum number of bytes to return from $stream. If additional bytes are available, they will be read and discarded.
string$descriptionHuman-readable description of stream, for exception message.
int$lengthMaximum number of bytes to read.
Return
stringThe data read from the stream.

public function __destruct()

This method is not documented.
Return
void

private function closeProcess()

Close and free resources if necessary.

Return
void

private function procGetStatus()

Execute proc_get_status(), but avoid pitfalls.

Return
dictProcess status.

private function tryToCloseStdin()

Try to close stdin, if we're done using it. This keeps us from hanging if the process on the other end of the pipe is waiting for EOF.

Return
void

private function getNextTimeout()

This method is not documented.
Return
wild

private function sendTerminateSignal()

This method is not documented.
Return
wild

private function waitForExit($duration)

This method is not documented.
Parameters
$duration
Return
wild

private function getStdoutBufferLength()

This method is not documented.
Return
wild

private function getStderrBufferLength()

This method is not documented.
Return
wild