|
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.
|