Sometimes Windows makes me want to kill myself.
It was a simple enough idea: I've got a task to be performed, which can take anywhere from several seconds to a minute or two. I want to activate it from a web page, and display a progress bar to the user. To make this work on the web, of course, this means the initial request has to spawn a background process and terminate, then I'll use AJAX to make subsequent calls to another script that checks on the progress, and update the progress bar every couple of seconds.
It's a little more complex than you might expect, if you're not familiar with web development. But on UNIX-based systems, it's really not that complicated. Unfortunately, I needed to do this on a Windows server.
It turns out that Windows doesn't have anything equivalent
to fork()
. PHP's
pcntl_fork()
doesn't exist on Windows. Perl's fork()
is a
crazy hack
that uses threads to emulate pseudoprocesses, but the parent
thread can't exit until the child threads are done. It's
supposed to be possible
to create a WScript.Shell COM object and call the
Run method,
but while this worked fine when I tried it from command line, I
couldn't get it to work when running it from a web page. There were
no error messages anywhere I could find, so I still don't know
why that didn't work.
Eventually I downloaded the PsTools
package from SysInternals, and was able to use psexec -d
to successfully spawn a background process. Unfortunately the first
time you run it, a dialog box pops up and requires you to accept a
license agreement, which is a little awkward when you're trying to
run it from within a web server. However, I was able to use the
RunAs
command (Windows' equivalent to sudo
) to run
psexec
as the web server user and acknowledge the
resulting dialog box that way.
There was just one other minor hurdle: even though I set
$|=1
to explicitly disable output buffering in the
Perl script that I eventually got running as a background process,
it apparently still buffers output somewhere, because the file I
was writing my progress to remained 0 bytes until the file was
closed. I had intended to keep the file open for writing, appending
to it as I went. I figured out a better way to report progress,
so now I'm repeatedly opening the file, writing to it, and closing
it again, but without keeping a running transcription of every last
detail.
In the end, I got it working, and the resulting progress bar works perfectly. It was quite an adventure in frustration and annoyance, but now I know what to expect if I ever need to do something like this again.