2013-04-08 5 views
6

ich einen Server mit Rook in R erstellt haben - http://cran.r-project.org/web/packages/Rook -Code ist alsRun R/Rook als Web-Server beim Start

#!/usr/bin/Rscript 
library(Rook) 
s <- Rhttpd$new() 
s$add(
    name="pingpong", 
    app=Rook::URLMap$new(
    '/ping' = function(env){ 
     req <- Rook::Request$new(env) 
     res <- Rook::Response$new() 
     res$write(sprintf('<h1><a href="%s">Pong</a></h1>',req$to_url("/pong"))) 
     res$finish() 
    }, 
    '/pong' = function(env){ 
     req <- Rook::Request$new(env) 
     res <- Rook::Response$new() 
     res$write(sprintf('<h1><a href="%s">Ping</a></h1>',req$to_url("/ping"))) 
     res$finish() 
    }, 
    '/?' = function(env){ 
     req <- Rook::Request$new(env) 
     res <- Rook::Response$new() 
     res$redirect(req$to_url('/pong')) 
     res$finish() 
    } 
) 
) 
## Not run: 
s$start(port=9000) 

$ ./Rook.r 
Loading required package: tools 
Loading required package: methods 
Loading required package: brew 
starting httpd help server ... done 

Server started on host 127.0.0.1 and port 9000 . App urls are: 

    http://127.0.0.1:9000/custom/pingpong 
Server started on 127.0.0.1:9000 
[1] pingpong http://127.0.0.1:9000/custom/pingpong 

Call browse() with an index number or name to run an application. 
$ 

folgt und der Prozess endet hier.

Sein feiner in dem R-Shell läuft, aber dann will ich es als Server beim Systemstart ausgeführt werden. So, sobald der Start aufgerufen wird, sollte R nicht beenden, sondern auf Anforderungen auf dem Port warten. Wie werde ich R davon überzeugen, einfach zu warten oder zu schlafen, anstatt zu beenden? Ich kann die Warte- oder Schlaffunktion in R verwenden, um einige N Sekunden zu warten, aber das passt nicht perfekt die Rechnung

Antwort

1

ist ein Vorschlag:

Erste Split das Beispiel, das Sie gab in (mindestens) zwei Dateien: Eine Datei enthält die Definition der Anwendung, die in Ihrem Beispiel ist der Wert des app Parameters zur Rhttpd$add() Funktion. Die andere Datei ist die RScript, die die in der ersten Datei definierte Anwendung startet.

Zum Beispiel, wenn der Name Ihrer Anwendung Funktion pingpong in einer Datei Rook.R namens definiert benannt, dann die Rscript könnte wie etwas aussehen:

#!/usr/bin/Rscript --default-packages=methods,utils,stats,Rook 

# This script takes as a single argument the port number on which to listen. 

args <- commandArgs(trailingOnly=TRUE) 

if (length(args) < 1) { 
     cat(paste("Usage:", 
       substring(grep("^--file=", commandArgs(), value=T), 8), 
       "<port-number>\n")) 
     quit(save="no", status=1) 
} else if (length(args) > 1) 
    cat("Warning: extra arguments ignored\n") 

s <- Rhttpd$new() 
app <- RhttpdApp$new(name='pingpong', app='Rook.R') 
s$add(app) 
s$start(port=args[1], quiet=F) 

suspend_console() 

Wie Sie sehen können, nimmt das Skript eine Argument, das den Überwachungsport angibt. Nun können Sie ein Shell-Skript erstellen, das dieses Rscript mehrfach aufruft, um mehrere Instanzen Ihres Servers zu starten, der auf verschiedenen Ports abhört, um eine gewisse Parallelität bei der Beantwortung von HTTP-Anfragen zu ermöglichen.

Zum Beispiel, wenn die Rscript oben in einer Datei start.r benannt ist dann ein solches Shell-Skript könnte etwa wie folgt aussehen:

#!/bin/sh 

if [ $# -lt 2 ]; then 
    echo "Usage: $0 <start-port> <instance-count>" 
    exit 1 
fi 

start_port=$1 
instance_count=$2 
end_port=$((start_port + instance_count - 1)) 

fifo=/tmp/`basename $0`$$ 

exit_command="echo $(basename $0) exiting; rm $fifo; kill \$(jobs -p)" 
mkfifo $fifo 

trap "$exit_command" INT TERM 

cd `dirname $0` 

for port in $(seq $start_port $end_port) 
    do ./start.r $port & 
done 

# block until interrupted 
read < $fifo 

Die obige Shell-Skript zwei Argumente verwendet: (1) die niedrigste Port -num zu hören und (2) die Anzahl der Instanzen zu starten. wenn der Shell-Skript in einer ausführbaren Datei ist start.sh Zum Beispiel genannt dann

./start.sh 9000 3 

drei Instanzen Ihrer Rook Anwendung starten zu hören auf dem Ports 9000, 9001 und 9002, respectively.

Sie sehen die letzte Zeile des Shell-Skript aus dem Fifo liest, die von dem Verlassen des Skript verhindert, bis sie von einem empfangenen Signal verursacht. Wenn eines der angegebenen Signale abgefangen wird, führt das Shell-Skript alle Rook Serverprozesse aus, die es gestartet hat, bevor es beendet wird.

Jetzt können Sie einen Reverse-Proxy konfigurieren, dass eingehende Anfragen zu einem der Server-Instanzen zu übermitteln.wenn Sie Nginx Zum Beispiel verwenden, können Sie Ihre Konfiguration in etwa so aussehen:

upstream rookapp { 
    server localhost:9000; 
    server localhost:9001; 
    server localhost:9002; 
} 
server { 
    listen your.ip.number.here:443; 
    location /pingpong/ { 
     proxy_pass http://rookapp/custom/pingpong/; 
    } 
} 

Dann Ihr Dienst auf dem öffentlichen Internet verfügbar sein.

Der letzte Schritt ist es, ein Steuerskript mit Optionen zu erstellen, wie start (den oben Shell-Skript aufrufen) und stop (es senden TERM Signal Ihre Server zu stoppen). Ein solches Skript behandelt beispielsweise das Ausführen des Shell-Skripts als Daemon und das Verfolgen der Prozess-ID-Nummer. Installieren Sie dieses Steuerungsskript an der entsprechenden Position, und es startet Ihre Rook Anwendungsserver, wenn der Computer gestartet wird. Wie das geht, hängt von Ihrem Betriebssystem ab, dessen Identität in Ihrer Frage fehlt.

Hinweise

  1. Ein Beispiel dafür, wie die Fifo in dem Shell-Skript verwendet werden, können verschiedene Aktionen auf Basis von empfangenen Signalen zu nehmen, sehen this stack overflow question.

  2. Jeffrey Horner hat ein Beispiel a complete Rook server application zur Verfügung gestellt.

  3. Sie werden sehen, dass das obige Shell-Skript nur die Signale INT und abfängt. Ich wählte diese, weil INT Ergebnisse von Typisierung-C am Terminal und ist das Signal von Steuerskripts auf meinem Betriebssystem verwendet, um Dienste zu stoppen. Vielleicht möchten Sie die Auswahl der zu überwachenden Signale abhängig von Ihren Umständen anpassen.

0

Haben Sie das versucht? Hier

while (TRUE) { 
    Sys.sleep(0.5); 
}