jellisii has asked for the wisdom of the Perl Monks concerning the following question:

I have a CGI calling an external perlscript that I've written that is supposed to do the following:

foreach $i @list { Process this command; sleep $time; }
It works from the command prompt, but from the Web, it never appears to sleep properly before processing the next loop. Is this a known problem with CGI or am I just special? :)

Replies are listed 'Best First'.
(Ovid) Re: CGI and Sleep?
by Ovid (Cardinal) on Jun 26, 2001 at 04:00 UTC

    First off, you should have parentheses around the @list or else this is not valid syntax. Since we don't have a correct code snippet, it's tough to see what the problem is. Further, are you using strict and warnings? If so, you may get some useful information in your error log that would guide you. My main question, though, is "how are you setting $time"? I know of no reason why it wouldn't operate properly via the Web.

    Frankly, though, I've never used this with a CGI script. If a script takes too long to return an answer, the server may issue a 408 Request Time-out status to the browser and kill the process. If you provide us with a bit more code, we may be able to answer your question or provide you with an alternate solution.

    Cheers,
    Ovid

    Vote for paco!

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      I'm almost ashamed to show how amature my code is, but here it is...
      #!/usr/bin/perl -w close STDOUT; @playlist = `cat ./playlist.txt`; $totalnum = scalar(@playlist); foreach $i (@playlist) { # a random number for the randomizer. $random = int(rand $totalnum); # use that random number to determine a file to play. $filename = $playlist[$random]; # format the file name so I can *USE* it. # the first regex escapes symbols for me. the second, spaces. $filename =~ s/(')|(&)|(\()|(\))/\\$+/g; $filename =~ s/\s/\\\ /g; # play the file, throw that process into the bg system("/usr/local/bin/ogg123 -d oss -q $filename &"); # write the PID and filename to a file # need this sleep in here to make shure the player starts before I t +ry # to write the PID sleep 2; system("ps -U root --format pid --format fname| grep ogg123> ./playe +r.pid"); open(PLAYING, ">./nowplaying.txt"); print PLAYING $filename; close PLAYING; # decriment the total number of files left to play. $totalnum--; # remove the filename from the list. splice @playlist, $random, 1; # get the information for the file that is playing. $playtime = `ogginfo $filename| grep length=`; # get the total playtime in secs for the file. $playtime =~ s/length=//; # pause for that many seconds, as to not play multiple files # simultaneously :) sleep $time; }

      I shut off STDOUT so the CGI calling this script won't wait for this to execute.

        This may be a typo. strict would have caught it.

        sleep $playtime;

        Here's a very quick rewrite. It's untested, but it's a little nicer, in my opinion.

        #!/usr/bin/perl -w use strict; close STDOUT; open(LIST, 'playlist.txt') or die "Can't open playlist: $!"; my @playlist = <LIST>; close LIST; while (@playlist) { my $pos = rand @playlist; my $filename = playlist[$pos]; system("/usr/local/bin/ogg123", '-d', 'oss', 'q', $filename, '&'); sleep 2; foreach (`ps -U root --format pid fname`) { next unless /ogg123/; open(PID, '>player.pid') or warn "Can't log pid ($_): $!"; print PID $_; close PID; last; } open(PLAYING, ">nowplaying.txt") or warn "Can't log filename $file +name: $!"; print PLAYING $filename; close PLAYING; splice @playlist, $pos, 1; my $playtime; foreach (`ogginfo $filename`) next unless /length=(.+)$/; $playtime = $1; last; } sleep $playtime; }
Re: CGI and Sleep?
by voyager (Friar) on Jun 26, 2001 at 04:09 UTC
    It may be that it's working but buffering is hiding the fact. In your script you need to set:
    • $| = 1;
    • make sure you print results as you generate them, rather than printing all the results at the end.
    • my browser (IE5.5/windows) won't print "anything" until a certain number of bytes are printed, so you may want to print a long string at the start to prime things.
    • oddly, i have found that under mod_perl i don't need as long a string to "get things started" as i do under straight cgi
      What is this supposed to be doing exactly? It kind of looks like you're using a perl cgi to manage some kind of audio playlist? Maybe shoutcast or something? I'd try and find a way to append this information to a playlist instead of executing whatever it is you're executing over and over again.

      Cgi and sleep don't tend to go well together, because cgi is really for an execute-once and then expire kind of thing. You might want to actually have a separate server daemon that gets fed info from the cgi but always runs on its own and can handle queuing your selections ... my 2 quatloos ...

      -mr.dunstan
        I've got a Linux machine (using alsa drivers and a monster 3d sound card that was lying around) sitting under my stereo playing audio files for me. I wanted it headless (I'm very space limited, and most of the time I or my roommates are at PCs when this is playing anyway), so I'm doing all of the control from a web form. I'd do it all from console, but It's a bit daunting for my roommates to handle that, plus, I thought it'd be an easy project... geuss I was wrong on *that* one! :) If there's a better way, I'm open to suggesstions!
Re: CGI and Sleep?
by nysus (Parson) on Jun 26, 2001 at 04:07 UTC
    Is this script outputting to the browser? If so, try '$|++;' near the top of the script to turn off buffering of the output.

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot";
    $nysus = $PM . $MCF;