Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Windows Services, Win32::Daemon, Threading, and SOAP::Lite

by hackdaddy (Hermit)
on Nov 12, 2005 at 02:15 UTC ( [id://507915]=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 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.

If a new job is requested, I spawn a new thread to run the job and then detach to let the main service thread loop again. In the job thread, I can communicate with the Apache server using SOAP to update the database that the job is complete.

On start up of the Windows Service, I start a new thread and detach to create a SOAP daemon using SOAP::Transport::HTTP::Daemon. This means that I can make SOAP requests into the Windows Service to get information about how many jobs have been run, time running, threads completed, thread count, etc.

I would like to be able to communicate using SOAP from the Apache CGI/Perl web front end to get the current status and administrate the Windows Service. For instance, I would like to change logging settings or tell a thread running a job to terminate the job.

My question is how do I make the design of this Windows Service clean and how do I share data between threads and packages?

Any assistance will be greatly appreciated. Thanks.

  • Comment on Windows Services, Win32::Daemon, Threading, and SOAP::Lite

Replies are listed 'Best First'.
Re: Windows Services, Win32::Daemon, Threading, and SOAP::Lite
by BrowserUk (Patriarch) on Nov 12, 2005 at 04:21 UTC
    My question is how do I make the design of this Windows Service clean...

    By doing a good job :) That sounds flippant, but "clean" is such an 'airey-fairy' and subjective term that it is impossible to answer. What you, me and 10 others would call 'clean' are probably a dozen different things.

    Is there some part of your app, which from the above seems well thought through, that you are having your doubts about your current implementation? Specific questions (with code) are generally easier to attempt good answers to.

    ... how do I share data between threads and packages?

    Assuming you've seen threads::shared, what problems are you having? Again, specific examples and code are good idea.

    Generally, share data not code. Objects contain both and do not easily move between threads.


    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.
      "clean" is such an 'airey-fairy' and subjective term that it is impossible to answer

      Entirely true, of course. However, in my short time on PM, I've learned that most monks seem to give petitioners the benefit of the doubt on what "clean" means and infer, instead, that they really mean "recommended best practices". Yes, we can still get 12 opinions from 10 people (I realise this isn't exactly what you said - I can count ;-}), but perhaps that will help narrow down the question. I don't think "best practices" are quite so subjective. Still subjective, but should be much less so.

        ... most monks seem to give petitioners the benefit of the doubt on what "clean" means and infer, ...

        For some, maybe most questions, I agree with you that what would consistitute 'clean' or 'best practice' is fairly obvious and you can infer, and answer on that basis. For this particular question, I think it is much less clear.

        If you were to take a survey of the Monks asking them about the four components of the OPs title, I would not be at all surprised if you got a large percentage, maybe even a majority, that would suggest that anything that used threads, or anything that used Win32 for that matter, could never be considered clean.

        From my personal bias, I have no problem with those two, but SOAP (and many things that utilise XML) just seems like a cumbersome and clumsy way of doing what could be done more simply and easily without.

        From the description given, the OP appears to have already given considerable thought to the overall requirements of his task, and chosen a workable and possibly optimal solution for it's implementation given the environment in which he needs to operate.

        Given that level of detail of his design, I could not see a way to make positive suggestions in the absence of either working code that could be made 'more clean', or specific implementation problems to solve.

        Without sight of his code to critique, nor problems to address, the only advice I could see as applicable, was "Do a good job".

        If you have better insight as to what changes he should make his code, or design alternatives he should consider, without requiring further information, by all means offer them--to him.


        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: Windows Services, Win32::Daemon, Threading, and SOAP::Lite
by renodino (Curate) on Nov 12, 2005 at 16:02 UTC
    Simple solution (assuming you're just passing scalar values to your worker threads):
    use Thread::Queue; # in your "job shutdown" dispatcher: # # start the worker threads, passing the $q # my @workers = (); my %queues = (); my $q; $q = Thread::Queue->new(), push(@workers, threads->new(\&run, $q)), $queues{$workers[-1]->tid()} = $q foreach (1..$threadcount); # # wait for them all to tell you they're ready # my $resp = $_->dequeue() foreach (values %queues); # # now do yer thang...when you get a "shutdown event": # $queues{$killtid}->enqueue('Kill job');
    and a stripped down worker thread:
    sub run { my $q = shift; $q->enqueue('ready'); # # need to sleep or otherwise wait for the # spawner to read the queue # while (1) { my $cmd = $q->dequeue(); # # process the command; you'll need to # add a timer to come back and check it # } }
    All that being said, if you need to pass around more complex resource objects between threads, you might consider Thread::Queue::Duplex, and make your object threads::shared, e.g.,
    package WorkerResource; use Thread::Queue::Queueable; use base qw(Thread::Queue::Queueable); sub new { my $class = shift; my %obj : shared = (); # # ...do some object init.. # return bless \%obj, $class; } # # overload Thread::Queue::Queueable marshal methods # sub curse { # # marshall any complex object members into something # that can be passed over a Thread::Queue::Duplex, # i.e., either a scalar, or a threads::shared ref # note that, if your object is threads::shared, # it implies all its members are either scalar or # threads::shared, so you can use the default TQQ::curse() # # } sub redeem { my ($class, $obj) = @_; # # unmarshall any complex object members and rebless the # object back into its class. # note that, if your object is threads::shared, # it implies all its members are either scalar or # threads::shared, so you can use the default TQQ::redeem(), # which just blesses # } package main; my $q = Thread::Queue::Duplex->new(); my $thread = threads->new(\&run, $q); my $resource = WorkerResource->new(); my $msgid = $q->enqueue($resource); my $result = $q->wait($msgid);
    If the resource you're passing between threads needs read/write locking, check Thread::Resource::RWLock.

    However, be careful of passing around closures and filehandles. The former just won't work; the latter needs some magic to convert to fileno's in curse() and back to handles in redeem().

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (None)
    As of 2024-04-25 00:45 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found