2

I am trying to write a wrapper around a simulator which provides a web API so that users can spawn off simulations on a server and collect the results.

My initial design was to have a php simulation StartSimulation.php running in Apache which will fork & exec the simulation, and pipe the results to a file. However, you cannot fork & exec in php inside an apache module. Furthermore, it gets a bit messy in this implementation because there is no processes managing the orphaned simulations, so it is tricky to kill them and count them. It seems a bit difficult to use a standard web server since there is no global state which stores the list of running processes (simulations).

The simulator is written in c++, but It should be modified as little as possible. I prefer to write a wrapper for it and exec the simulator and capture its stdout and make that accessible to the user.

Basically, the wrapper should have an web-accessible API with 3 commands.

1.) start_simulation - which basically forks & execs an instance of the simulator, recording its pid in a table, and piping its stdout to a known buffer. The wrapper should not allow more than 16 instances of the simulator to run on the server. If successful, it returns a simulation code to the user. Otherwise, it returns an error code.

2.) stop simuation - takes the simulation code returned in (1), and kills the associated process.

3.) get_process - takes the simulation code returned in (1), looks up the known buffer which holds the stdout for that process, and returns that information to the user.

Should I write a custom application server for this? If so, is there a nice package with some starter code?

Thanks Kyle

Kyle
  • 29
  • 2
  • http://stackoverflow.com/questions/6915191/simple-ipc-between-c-and-python-cross-platform/6915365#6915365 might be of interest to you – jterrace Aug 22 '11 at 22:15
  • possible duplicate of [Best way to manage long-running php script?](http://stackoverflow.com/questions/2212635/best-way-to-manage-long-running-php-script) – symcbean Apr 26 '12 at 15:51

1 Answers1

1

I know this is an old question but hopefully this will still prove helpful to somebody...

Having the process management (fork/exec/wait/kill/signal etc.) in a PHP script called directly from Apache via an http request is definitely not the way to go. As you say, it gets messy very quickly :)

I would suggest that the PHP script called via http is simply a command proxy to a simple server process. If PHP is your preferred language, you can implement both this way.

For example, you can do this with message queues as follows...

  1. You can create a fairly simple PHP server that creates a message queue and wait for messages to come in. It can then do the work of starting or stopping simulator processes

  2. The remote user selects an operation (start, stop, get output) via a web page form.

  3. This results in an HTTP/POST request sending the form data to your PHP script (I'd do this as an AJAX call so I can send the data and interpret the result without reloading the page)

  4. Your server-side PHP script can interpret the form data and send a command via a message to the PHP server process

Let's illustrate this with some PHP code. I'm keeping this trivial and unsophisticated in the interests of brevity.

PHP Script (web form target)

This is where we interpret our incoming form request and turn it into a message for the server process

<?php
/*
 * Responses are sent as simple text strings to be interpreted by
 * the client-side JavaScript handling this AJAX call. Responses
 * starting with 'ERR:' are errors, responses starting with 'ACK:'
 * are acknowledgements. Simply check the first few characters of
 * the response in the client-side JavaScript.
 */
header('Content-Type: text/plain; charset=UTF-8);

/*
 * Here we define some message types, one per command. These should correspond
 * to the command string sent from the web form
 */
$command = array(
    'START_SIM'  => 1,
    'STOP_SIM'   => 2,
    'GET_STATUS' => 3,
    'GET_OUTOUT' => 4
);

$queue_id = 0xbeef;             /* An arbitrary message queue id */
$cmd = $_REQUEST['command'];    /* The command from the web form */

/* get simulator instance id to act upon, if specified */
if (isset($_REQUEST['id']))
    $sim_id = $_REQUEST['id'];
else
    $sim_id = '';               /* no sim id? probably a create command */

/* check the message queue exists... */
if (msg_queue_exists($queue_id) === false) {
    echo 'ERR:Message queue not found!';
    return;
}

/* open the message queue and pass the command on to the server... */
if (($qhandle = msg_get_queue($queue_id)) === false) {
    echo 'ERR:Failed to open message queue to server';
    return;
}

if (msg_send($qhandle, $command[$cmd], $sim_id) === false)
    echo 'ERR:Failed to send command';
else
    echo 'ACK:Command sent ok';
?>

PHP Server (run separately on your web server)

And here's an equally simple server...

<?php
/*
 * assume the same queue id's and defines as in the
 * client code above, etc..
 */

if (($qhandle = msg_get_queue($queue_id)) === false) {
    /* emit failure message to log file etc.. */
    ...
    return;
}

while (1) {
    if (msg_receive($qhandle, 0, $msgtype, $message,
        true, 0, $rc) === false) {
            /* log error message ... */
    } else {
        /*
         * Get the client id (in case you want to send
         * a reply back to the client) and the
         * message data, which is the simulation id.
         *
         * Remember that we use the message type to
         * indicate the command being requested
         */
        $client = $message['client'];
        $sim_id = $message['msg'];
        evaluate_command($client, $msgtype, $sim_id);
    }
}
?>

Obviously this is horribly simple, has no error checking and you'll need to write the "evaluate_command()" function yourself. I've just scribbled this down to illustrate the idea (and I've written this off the cuff, so it may be replete with other errors too!)

Jimmo
  • 56
  • 2