Oto jedna sugestia:
Pierwszy rozłam przykład dałeś do (przynajmniej) dwa pliki: jeden plik zawiera definicję aplikacji, które w swoim przykładem jest wartość parametru app
do funkcji Rhttpd$add()
. Drugi plik to RScript, który uruchamia aplikację zdefiniowaną w pierwszym pliku.
Na przykład, jeśli nazwa funkcji aplikacji jest nazwany pingpong
zdefiniowane w pliku o nazwie Rook.R
, wówczas Rscript może wyglądać:
#!/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()
Jak widać, ten skrypt ma jedną argument określający port nasłuchiwania. Teraz możesz utworzyć skrypt powłoki, który będzie wielokrotnie wywoływał ten kod, aby uruchomić wiele instancji serwera nasłuchujących na różnych portach, aby umożliwić pewną współbieżność odpowiedzi na żądania HTTP.
Na przykład, jeśli Rscript powyżej znajduje się w pliku o nazwie start.r
wówczas taki skrypt może wyglądać mniej więcej tak:
#!/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
Powyższy skrypt przyjmuje dwa argumenty: (1) najniższy portu -Numer do nasłuchu i (2) liczba instancji do uruchomienia. Na przykład, jeśli skrypt jest w pliku wykonywalnego o nazwie start.sh
następnie
./start.sh 9000 3
rozpoczną trzy instancje swojej Rook aplikacji nasłuchuje na portach 9000, 9001 i 9002, odpowiednio.
Widzisz ostatni wiersz skryptu powłoki czyta z fifo, który uniemożliwia skryptowi wyjście, dopóki nie zostanie wywołany przez odebrany sygnał. Gdy jeden z określonych sygnałów zostanie uwięziony, skrypt powłoki zabije wszystkie procesy serwera, które zostały uruchomione przed jego wyjściem.
Teraz możesz skonfigurować odwrotne proxy, aby przekazywać przychodzące żądania do dowolnej instancji serwera.Na przykład, jeśli używasz Nginx, konfiguracja może wyglądać mniej więcej tak:
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/;
}
}
Następnie usługa może być dostępna w publicznej sieci Internet.
Ostatnim krokiem jest stworzenie skrypt sterujący z opcjami takimi jak start
(aby wywołać powyższy skrypt) i stop
(aby wysłać mu sygnał do zatrzymania TERM
serwerów). Taki skrypt obsłuży takie rzeczy, jak uruchomienie skryptu powłoki jako demona i śledzenie jego numeru identyfikacyjnego procesu. Zainstaluj ten skrypt sterujący w odpowiedniej lokalizacji i uruchomi on serwery aplikacji podczas uruchamiania. Sposób wykonania zależy od systemu operacyjnego, którego tożsamości brakuje w pytaniu.
Uwagi
Na przykład, jak kolejka w skrypcie powłoki mogą być wykorzystywane do podejmowania różnych działań na podstawie odebranych sygnałów, patrz this stack overflow question.
Jeffrey Horner podał przykład a complete Rook server application.
Zobaczysz, że przykładowy skrypt powłoki powyżej pułapek tylko sygnały INT
i. Wybrałem te, ponieważ INT
wynika z wpisania control-C na terminalu i TERM
jest sygnałem używanym przez skrypty sterujące w moim systemie operacyjnym, aby zatrzymać usługi. Możesz dostosować wybór sygnałów do pułapki w zależności od okoliczności.