2015-05-19 11 views
9

mi potete aiutare, perché ho a volte (50:50):Xvfb-run inaffidabili quando più istanze invocate in parallelo

webkit_server.NoX11Error: Cannot connect to X. You can try running with xvfb-run. 

quando inizio lo script in parallelo:

xvfb-run -a python script.py 

È possibile riprodurre questo te stesso in questo modo:

for ((i=0; i<10; i++)); do 
    xvfb-run -a xterm & 
done 

Delle 10 istanze di xterm, si avvia, 9 di esse generalmente falliscono, uscendo con il messaggio Xvfb failed to start.

+1

Cosa in particolare hai provato? Non vorremmo suggerire quello che sai non funzionerà. –

+0

che hai detto, dici "parallelamente" - significa che stai iniziando un numero di istanze allo stesso tempo? Potevo vedere che c'era una condizione di competizione nell'allocazione portuale. –

+0

Prova a passare un argomento unico - --server-num' a ogni istanza di 'xvfb-run', piuttosto che affidarti a' -a' per gestire correttamente le potenziali razze. –

risposta

20

Guardando xvfb-run 1.0, funziona come segue:

# Find a free server number by looking at .X*-lock files in /tmp. 
find_free_servernum() { 
    # Sadly, the "local" keyword is not POSIX. Leave the next line commented in 
    # the hope Debian Policy eventually changes to allow it in /bin/sh scripts 
    # anyway. 
    #local i 

    i=$SERVERNUM 
    while [ -f /tmp/.X$i-lock ]; do 
     i=$(($i + 1)) 
    done 
    echo $i 
} 

Questo è molto cattiva pratica: se due copie di find_free_servernum corsa, allo stesso tempo, non saranno a conoscenza degli altri, in modo che sia può decidere che lo stesso numero è disponibile, anche se solo uno di essi sarà in grado di usarlo.

Così, per risolvere questo problema, scriviamo il nostro codice per trovare un numero di display libera, invece di assumere che xvfb-run -a funzionerà in modo affidabile:

#!/bin/bash 

# allow settings to be updated via environment 
: "${xvfb_lockdir:=$HOME/.xvfb-locks}" 
: "${xvfb_display_min:=99}" 
: "${xvfb_display_max:=599}" 

# assuming only one user will use this, let's put the locks in our own home directory 
# avoids vulnerability to symlink attacks. 
mkdir -p -- "$xvfb_lockdir" || exit 

i=$xvfb_display_min  # minimum display number 
while ((i < xvfb_display_max)); do 
    if [ -f "/tmp/.X$i-lock" ]; then    # still avoid an obvious open display 
    ((++i)); continue 
    fi 
    exec 5>"$xvfb_lockdir/$i" || continue   # open a lockfile 
    if flock -x -n 5; then       # try to lock it 
    exec xvfb-run --server-num="$i" "[email protected]" || exit # if locked, run xvfb-run 
    fi 
    ((i++)) 
done 

Se si salva questo script come xvfb-run-safe, si può quindi richiamare :

xvfb-run-safe python script.py 

... e non preoccuparti di condizioni di gara a condizione che nessun altro utente sul sistema sono in corso anche Xvfb.


Questo può essere testato in questo modo:

for ((i=0; i<10; i++)); do xvfb-wrap-safe xchat & done 

... nel qual caso tutti i 10 casi in modo corretto avvio e vengono eseguite in background, al contrario di:

for ((i=0; i<10; i++)); do xvfb-run -a xchat & done 

... dove, in base alla tempistica del sistema, nove su dieci (in genere) falliscono.

+0

Nizza. Avevo solo bisogno di qualcosa di simile per le esecuzioni parallele di script 'xvfb-run' - e questo funziona come un incantesimo. Quindi grazie! –

+5

Vorrei che questa modifica fosse incorporata in 'xvfb-run'. –