How to handle intermittent errors in Console output to network file

211 views Asked by At

I've written a Console application that is typically run via Task Scheduler with no user present. If appropriate, it redirects Console output to a file (with the app-start timestamp in the name) that happens to be on a network.

I've seen a few cases -- they are rare -- where it seems that the file contents ends prematurely (that is, later messages generated by the program are not there). Output from a third-party logging tool (Gibraltar Loupe) has shown me that calls to Console.WriteLine can fail if there is a network glitch causing the output file to be unavailable temporarily, causing an unhandled exception.

(Once, the normal app's normal exception handling was -- somewhat remarkably -- able to write the message about the unhandled exception that resulted when Console.WriteLine failed due to "The specified network name is no longer available" -- that must have been a very temporary glitch!)

I can't think of an approach other than to replace all calls to Console.WriteLine with calls to something of my own that traps such errors, waits until the network is again available, and tries again. (Or possibly it could redirect output to a local file for the rest of the run, but other things would likely fail if the network stays unavailable.)

Replacing all calls to Console.WriteLine in an app with hundreds of them will lead to a major source-code-changes explosion, forcing changes in files that haven't changed in many months. Do I have a choice?

Does anyone have a different suggestion for how to handle this (other than to have abstracted away Console.WriteLine from the beginning of the project)?

Thank you for any suggestions.

2

There are 2 answers

2
Hans Passant On BEST ANSWER

Not the greatest idea to try to tackle a flaky hardware problem in software. But consider:

  • Redirect to a local file, use another scheduled task to move the files.
  • Write a little guard app that uses Process.Start() to start this app. And uses Process.ExitCode to see how it fared. It can restart the app, multiple times if necessary, delaying longer between each attempt.
  • Reassign Console.Error and Console.Out with your own TextWriter derived class. Override Write(char) and call the original Error/Out.Write(char) method, wrapped in a try/catch. Try multiple times on failure, delaying longer between attempts.

You probably think the last one is attractive. Sample code:

using System.IO;

class MyWriter : TextWriter {
    private TextWriter writer;
    public MyWriter(TextWriter writer) { this.writer = writer; }
    public override Encoding Encoding { get { return writer.Encoding; } }

    public override void Write(char value) {
        for (int delay = 1; ; delay *= 2) {
            try { writer.Write(value); return; }
            catch { if (delay > 3600) throw; }
            System.Threading.Thread.Sleep(1000*delay);
        }
    }
}

class Program {
    static void Main(string[] args) {
        Console.SetOut(new MyWriter(Console.Out));
        Console.SetError(new MyWriter(Console.Error));
        // etc...
    }
}
0
chris.ellis On

To be honest, I think that abstracting away the Console.WriteLine is exactly what you want to do. It would allow you to build in an exception handling and retry policy, or allow your application to continue processing the rest of whatever it should be doing when the file is available again. It would also help with UnitTesting and abstraction and etc etc.

However, having said that. You could write to a local file during the execution of your task, and then move the file to your network share. This would then mean you should be able to "trust" that Console.WriteLine will stop working which should obviate the need to wrap every call. Then at the end of the task you can move the file to your network location. You can wrap this moving logic up in a whole bunch of error handling and retry logic which wont impact on your existing code.