1

I have an windows service that monitors a folder for new files being created.when a file gets added to the folder, the service will send the file for processing to a 2nd application. The 2nd app is actually a console app but is set as 'Windows Application' to avoid creating of the console window. The service and the 2nd app both run on a server. To implement only a single file to process each time, a semaphore has been implemented in the 2nd app, like so:

public class Program
{
    static Semaphore semaphore;
    [STAThread]
    static void Main(string[] args)
    {
        StartupConfigurator startConfig = new StartupConfigurator();
        semaphore = new Semaphore(1, 1, "2ndApp");
        semaphore.WaitOne();
        startConfig.StartProcessCommandLine(args);
        semaphore.Release(1);
        Environment.Exit(1);
    }
}

This works fine as long as the applicatin exits gracefully and the semaphore is released. In the 2nd app, there is a line of code which while executing just hangs (it is basically trying to login to a server, but fails, reasons are out of the scope for the 2nd app to know), it just hangs there. Because of the way the service is written, it will start an new instance of 2nd app everytime a new file is created. It can be adding of a new file or adding multiple files at once to the watched folder. For example, if 4 files are dropped to the watched folder, the service will launch 4 instances of the 2nd app. The 2nd app finishes a file, the semaphore is released and the next file is processed. This works fine if it does that way,i.e., it exits gracefully. In the case where it hangs, the only way to resume processing is to close all the instances from the Task Manager, ending just the troubled instance will not help either, all of them have to be ended.

There was discussion on the similar topic here but I am not able to know how to use it. Is there a way to for the 2nd app to know that it has been forcefully ended and the semaphore can be released.

Regards.

Community
  • 1
  • 1
Codehelp
  • 4,157
  • 9
  • 59
  • 96
  • I guess you should prevent the 2nd application from hanging... Put a time-out around the hangy operation. – zmbq Feb 22 '12 at 07:04
  • First, add a try/finally to make sure the semaphore gets released if an exception is thrown (this won't help if you kill it; it's just generally a good idea). Second, can't you make the login operation time out rather than hang indefinitely? – Sven Feb 22 '12 at 07:06

2 Answers2

0

Is there a way to for the 2nd app to know that it has been forcefully ended and the semaphore can be released.

No, when a process is killed, there is no chance to cleanup, execute finally blocks, etc. See this. Your best bet is to launch the hang-y operation on a separate thread and call join on the thread to wait for the operation to complete. A sample:

bool completed = false;
try
{
   Thread thread = new Thread(() => startConfig.StartProcessCommmandLine(args));
   thread.IsBackground = true;
   thread.Start();
   bool completed = thread.Join(60000); // 60s timeout
}
finally
{
   semaphore.Release(1);
}
Environment.Exit(completed ? 0 : 1);

Typically, an exit code of 0 is considered normal. The try/catch is important because if your thread throws an unhandled exception we want to make sure to release the semaphore before the process is brought down.

Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • Hi Mike, the login to server is not thread safe. I am thinking of wrapping the login line around a timeout and exit the method if it exceeds that. Any other ideas! – Codehelp Feb 22 '12 at 10:44
  • what do you mean by "login to server is not thread safe"? the above calls StartProcessCommandLine (assuming this does the login) on only one thread. if startConfig cannot be constructed on one thread and used in another then put it all on the other thread. i'm not sure how you plan to "wrap the login line around a timeout" without another thread unless there is some sort of timeout parameter for the login operation. – Mike Zboray Feb 22 '12 at 17:53
  • Hi Mike, the call StartProcessCommandLine does not do the login, it only starts a process which consists of a few steps, one of them being the Login. Now, the Login method is part of a third party library which, unfortunately, does not give a timeout when something goes wrong. The 'something' here is what I have no control on. So, I am going ahead with your suggestion of putting the login on a new thread and then exit once it timesout. Thanks for pointing in the correct direction. – Codehelp Feb 23 '12 at 06:31
0

If the second app is only started by the service, I would put the code that syncs the processing in the service.

The service will know if a processing app is started, and when that is finished, it will start another one. The app itself could have just a simple check if another app is already running (via semaphore or a mutex) and exit if it is.

This way the service could kill an unresponsive app, specify running timeouts, basically manage the processing.

SWeko
  • 30,434
  • 10
  • 71
  • 106