Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Debugging Windows Services created with Win32::Daemon

by hackdaddy (Hermit)
on Nov 15, 2005 at 20:04 UTC ( [id://508772]=perlquestion: print w/replies, xml ) Need Help??

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

I have created a multi-threaded Windows Service running on Windows Server 2003 using the Win32::Daemon module from http://www.roth.net/perl/Daemon.

I am using SOAP::Lite to communicate with an Apache CGI/Perl web front end for a MySQL database. In the main loop/thread, I make periodic SOAP requests to the Apache server to see if there are any jobs assigned in the database to the machine running the Windows Service daemon. I create a new thread when a new job request is found.

My problem is that after about two hours the Windows Service is mysteriously stopping without being sent a message to stop. I checked the application, security, and system logs and did not see anything.

I've used ptkdb before to debug Perl script, but what would be the best way to debug a Perl script that is running as a service?

How do I perform exception handling in a multi-threaded Perl script?

Any assistance is greatly appreciated. Thanks.

  • Comment on Debugging Windows Services created with Win32::Daemon

Replies are listed 'Best First'.
Re: Debugging Windows Services created with Win32::Daemon
by BrowserUk (Patriarch) on Nov 16, 2005 at 02:22 UTC

    I have two suggestions.

    1. Whilst developing your server, run it as a normal console application.

      The thing to remember is that everything inside the SERVICE_RUNNING branch of the top level if/then/elsif/else cascade (which is better replaced by a dispatch table!), is just "normal" code, except that it usually doesn't have access to a console.

      If you put your main logic within a subroutine and call it from that branch of the cascade (or dispatch to it), and you put that sub into a separate module, then writing a test harness that just loads that module and invokes the sub is trivial. You also get access to a console and can use what ever debug techniques (from print on up) that you would normally use to get your logic right.

      Once you are satisfied with your logic running as a console app, moving back to running it as a Service is easy. It will also highlight any problems that arise as a result of running as a service.

    2. If you find that when you make your tested app a service you still need to debug something that only shows up in the Service.

      Get yourself to http://www.smidgeonsoft.com/, and download PEBrowse Professional Interactive. And be sure to read the tutorial. There is a link to it at the bottom of that page.

      It will allow you to attach to the running Service, set break points, disassemble the code and supports using symbol files if you tell it where to look.

      Be warned. It operates at the assembler level, not the Perl source level, which takes some getting used to, but if you have thoroughly debugged your code before making it a Service, there are a limited number of thing s you will need to look at, and they are fairly simple to decipher at the assembler level.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Debugging Windows Services created with Win32::Daemon (STDERR)
by tye (Sage) on Nov 16, 2005 at 15:46 UTC

    I'd redirect STDERR to a file (and probably do that in a BEGIN block near the top of the main script file). When Perl dies, it almost always says something on the way down. I suspect Win32 is just throwing this information away.

    Using threads in Perl sounds like a recipe for having things die rather mysterious to me. So I'm not surprised you've experienced this.

    You might want to write a manager that gets run as a service and have it launch and re-launch the script that does the real work. It is also a good idea to have long-running processes restart themselves periodically. If you write the manager, then you could just have the worker script exit when idle if its been running longer than X. Getting the manager restarted periodically is trickier. On Unix, I'd just occasionally do exec($^X,$0,@ARGV), but I recall exec being more like system+exit in Win32 (despite MicroSoft claiming "the new process is placed in the memory previously occupied by the calling process") and that might not play well with the Service Control Manager or other bits.

    - tye        

      I'd redirect STDERR to a file (and probably do that in a BEGIN block near the top of the main script file).

      Using Win32::EventLog in conjunction with a __DIE__ handler would perhaps be a better solution.

      When Perl dies, it almost always says something on the way down. I suspect Win32 is just throwing this information away.

      Wouldn't a pucker *nix daemon also throw away any parting STDERR output? The done thing is to close all the standard filestreams isn't it?

      It's quite likely that (if enabled) any non-zero termination code or STDERR output would end up in the system or application portion of the event log


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        Using Win32::EventLog in conjunction with a __DIE__ handler would perhaps be a better solution.

        If you define "better" as "still throws away lots of possible sources of information". Eventually, I'd do both. As a first step in figuring out what is going wrong, I'd go with the much simpler approach that catches stuff other than just die cases. To illustrate just one case: I wouldn't be at all surprised if Perl, after reporting "panic: ...", might not survive long enough to make it all the way to the end of the non-trivial number of opcodes required to catch then get stuff into the event log.

        Wouldn't a pucker *nix daemon also throw away any parting STDERR output? The done thing is to close all the standard filestreams isn't it?

        A production-quality daemon usually redirects STDERR to /dev/null (closing is a bad idea). But a Unix daemon who doesn't do this could end up with its output automatically going to the system log (or, on some older Unixes, to "the console"). On some old Unix configurations, this could actually cause problems. My comment wasn't meant to be a dig against Win32. I still suspect that Win32 is just throwing away the information. And sometimes that has its advantages. No need to get defensive. (:

        It's quite likely that (if enabled) any non-zero termination code or STDERR output would end up in the system or application portion of the event log

        What does "if enabled" mean? If there is a Win32 option to redirect daemon output to the event log, then hackdaddy would probably appreciate a pointer to it. He reports that such isn't happening for him.

        - tye        

A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://508772]
Approved by herveus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2024-04-26 08:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found