Interoperating with Alfred
Requirements for Typical and "Persistent" Applications
Consider the following command specification taken from an alfred
script:
##AlfredToDo 2.0
Task "frame one" -cmds {
Cmd {render 001.rib}
}
When the dispatcher reaches this point in the job it will
fork
(2) a child process and use the
library routine execvp
(2) to launch the program
named "render" (assuming there is one in the current path).
The launch process is described in more detail in the
dispatching discussion.
Alfred-Compliant Application Behavior
Alfred expects that the applications it launches will follow
a few simple rules:
- exit status (return code) should be zero for successful completion;
alfred treats non-zero exit status as the indication of an error.
- it should keep stdin, stdout, and stderr open until exit
- it should stay in the foreground, i.e. it should not call
fork(2) itself and let the parent fork exit, since alfred will treat
this as the command completing.
These are standard attributes of many existing applications.
Alfred collects both stdout and stderr from the launched applications
and logs the output into an archive that can be retrieved by users on
a per-task basis using the UI.
Progress Indication and Alternate Exit Status
Applications can send a few special messages to alfred to trigger
certain special behavior. Sometimes it's useful for long-running commands,
such as renderings, to send percent-done messages to alfred so that it can
periodically update it's Task diagram to indicate command progress. Alfred
scans the stderr and stdout from the application looking for (newline-delimited)
lines of form:
ALF_PROGRESS nn%
where "nn" is an integer 0-100 which indicates the current
percent-completion of the command.
Similarly, lines of the form "ALF_EXIT_STATUS nnn" are used to
override the subsequent real exit status of the command. This is particularly
useful for applications which are launched indirectly via a call to rsh(1),
since rsh exits with its own status, not the status of the remotely launched
command.
Persistent Applications
In some circumstances it is useful for alfred to launch an application
once at the beginning of a job and subsequently send it command messages
throughout the lifetime of the job. Typically this is done to avoid
long launch times when multiple commands will be processing the same input
file or database, etc. These are called "persistent applications,"
an important example of which is the stand-alone version of
mtor,
which is used to process Maya® model files
that have been enhanced using the
MTOR
plug-in. For example, the stand-alone mtor is launched with the
name of a scene file, then messages are sent to its stdin
which cause it to generate RIB, or even run-time additions to the alfred job,
on demand.
In terms of the alfred scripting language, a persistent application is
simply one which:
- reuses Cmd launch expressions, i.e. each invocation in the job
has exactly the same command-line arguments.
- uses the Cmd "-msg" option to specify the unique action
associated with each invocation
- doesn't exit after processing a message
That is, the persistence is really a function of the application. It is launched
and sent the (optional) message just like any other command. If it processes
the message and exits, then alfred considers the command complete and goes on
to the next one. If it processes the message but does not exit, then alfred
looks ahead in the script to see if another instance of the same invocation
occurs, if so the next message is sent without relaunching the app when it
gets to that point in the script. Here is an example from our ATOR product...
[...]
Task "Frame.0000" -cmds {
Cmd {ator -alfred /tmp/xmp.wire.a005Ji} \
-msg {genWorklist 0 nohost flush} \
-tags {intensive} -expand 1
}
Task "Frame.0001" -cmds {
Cmd {ator -alfred /tmp/xmp.wire.a005Ji} \
-msg {genWorklist 1 nohost flush} \
-tags {intensive} -expand 1
}
[...]
In this case the application "ator" is launched to process
the "genWorklist 0 ..." command. The launch itself requires
the potentially lengthy start-up processing of a wire file. If ator
hasn't exited when the Frame.0001 task is started, then the
"genWorklist 1 ..." message is sent to the still-running app,
without requiring a reload of the wire file. Note: if ator did exit
between commands, then the normal command launching would occur again for
Frame.0001.
Note: by default alfred will attempt to launch as many Ready leaf nodes
as possible in parallel. This means that script writers need to take
care to avoid having parallel invocations of an application that was
intended to be persistent. One simple way to avoid multiple
invocations is to define a limit in the
alfred schedule for the app name. The default alfred schedule limits
the number of simultaneous local invocations of ator and mtor to one.
In the example above, the tag "intensive" is also
used to indicate that the given message will trigger a heavy-weight
operation, such as traversing a model and generating a RIB file. In
this case the script assumes that there is a limit of one
intensive Cmd allowed at a time (this is the setting in the
default schedule). Note that both the launched app name and any
explicitly listed tags are checked against the current limits; matching
service types can also be limited.
After all references to a persistent application have been processed,
alfred attempts to close the persistent application using an
increasingly severe series of actions.
First it will close the application's stdin pipe. If the application
doesn't exit, alfred then sends it a SIGTERM signal; and finally
if that hasn't worked, a SIGKILL is sent.
For an application to work as a persistent application:
- it should accept commands on stdin; each instance of the Cmd -msg
construct will pipe a new command to the app (via stdin). Commands should
be atomic (stateless) since parallelism and server-waits in the alfred
script can cause leaf-node Tasks to execute non-sequentially.
- it must handle semi-colon ";" as a command separator,
e.g. "cd /tmp; ls -l"
- it must respond to "echo text text text" by printing the
arguments to stdout, just like sh/csh
These last two points are crucial since alfred relies on these two
behaviors to determine when a message has been successfully processed
(in the current implementation each outgoing message has a feedback
"echo" command appended to it, when alfred gets this marker
back it knows the message has been processed).
Pixar Animation Studios
(510) 752-3000 (voice)
(510) 752-3151 (fax)
Copyright © 1996-
Pixar. All rights reserved.
RenderMan® is a registered trademark of Pixar. |