views:

111

answers:

4

I have a win service hosting a few workflows (a WorkflowApplication and a WorkflowServiceHost) that I need to keep long running. Because OnStart() requires that it completes and returns to the OS, I have a main method that fires on another thread in a threadpool. My Onstart() mainly looks like this

protected override void OnStart(string[] args)
{
     eventLog.WriteEntry("Service starting...");
     ThreadPool.QueueUserWorkItem(new WaitCallback(ServiceMainThread));
     Thread.Sleep(100);
     eventLogCms.WriteEntry("Service Started.");
}

ServiceMainThread() is the method where my workflows execute and core functionality is implemented. When I start the service on my Windows 7 machine it runs and then dies after approximately 8 minutes. On Win Server 2008, the thread NEVER executes.

So I think I've implemented threading incorrectly and what's ServiceMainThread is a bit shakey. I'm open to suggestions to what could be improved or any direction as I'm new to threading in .Net. Basic threading code in ServiceMainThread is coded as such:

private void ServiceMainThread(object state)
{
    // .. execute workflows ..
    eventLog.WriteEntry("Workflows executed.");

    while(alive)
    {
        Thread.Sleep(1);
        // ... check workflow states and ensure they're still executing ...
    }

    // .. halt workflow executions and perform persist operations if necessary ..
    eventLog.WriteEntry("Workflows halted.");
}

And for full illustrative purposes here is my OnStop() implementation:

protected override void OnStop()
{
    alive = false;
    this.haltEvent.WaitOne(); // haltEvent is of type ManualResetEvent 
}

Is there anything obvious that I could change to make my workflows remain in the execution state long term? The while loop seems a little too hackish (not to mention I don't like having to delay the thread for any amount of time as it is) and I'm sure there may be a better solution.

Using a Thread instead of a thread pool did ok starting but it seemed to allow the workflow run for 2minutes before execution started and stopping is now broken but I think I may be able to correct OnStop(). When I did that I set the while loop in ServiceMainThread() to an empty block so it doesn't block the thread the workflows are executing on.

Update: I get this exception from .Net in event logs:

Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
Stack:
   at Ptm.ServiceMainThread()
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadHelper.ThreadStart()

Server 2008 is 64-bit, could that have something to do with my issue?

+2  A: 

First, for a long-running thread, create your own Thread object and start it; don't use the ThreadPool. The thread pool is designed for small, relatively short-lived operations.

Second, there are several ways that you can keep your thread alive. The most basic is what you've tried, which is a while loop with a sleep (or other blocking) call at the end. This is the most basic, though not necessarily the "best". There are other options, like named WaitHandle objects that can be accessed from other applications, that can allow for more deterministic code execution and fewer iterations of wake-check-sleep.

If, however, you either can't (or don't want to) modify the other processes to support notifying your service of particular events, then what you have is, essentially, correct. I would, however, encourage selecting a more reasonable Sleep time; do you really need to check every millisecond?

Adam Robinson
I don't need to check every millisecond, I was just trying to implement blocking. I was having the thread sleep for 2 seconds at a time and it was delaying all my workflow execution by that time span. I have reason to suspect that it may be the reason why the workflows halt execution all together after ~8 minutes.
jlafay
@jlafay: Is this thread supposed to be *executing* the workflows? If so, it sounds like that should be taking place on another thread, not in the one that's supposed to monitor it.
Adam Robinson
@Adan: that's correct, it instantiates and then executes the two workflows that I wrote. They don't need to be monitored per se, I was trying different ways to perform blocking to keep while going. I've tried empty while blocks before with little success in other code.Do you have a basic "skeleton" that you could provide as an answer to my question that includes OnStart(), OnStop(), a main execution thread method and any other necessary code? A rough idea would help out greatly and I could take it from there.
jlafay
Should I possibly execute the workflows on a background worker thread asynchronously and have my dummy while loop checking to keep the service alive?
jlafay
@jlafay: You're overthinking this; as long as the process has active (non-background) threads, the service will continue to run. You don't need a "keep alive" thread. If you move your processing from the `ThreadPool` to a `Thread`, you shouldn't have an issue.
Adam Robinson
A: 

I solved that problem with my very long running Windows service by having OnStart() launch a System.Timers.Timer, and do all of the processing in the timer's ElapsedEventHandler.

Inside the handler I stop the timer, do the work on separate threads, check for a halt signal, and then restart the timer if it's OK to continue. The service's OnStop() method stops the timer and kills any active worker threads.

The worker threads handle all exceptions, so if one has a problem, it logs the exception, terminates, and then gets restarted on the next timer interval. The service core has never crashed.

ebpower
A: 

In regards to your blocking, you should probably use a Wait/Pulse Programming paradigm for signalling one thread to continue. Or to just Join the thread.

Wait & Pulse - Threading in C#

Aren