如何处理控制台输出到网络文件中的间歇性错误
How to handle intermittent errors in Console output to network file
我编写了一个控制台应用程序,通常 运行 通过任务计划程序在没有用户存在的情况下进行。如果合适,它将控制台输出重定向到恰好在网络上的文件(名称中带有应用程序启动时间戳)。
我见过一些情况——它们很少见——文件内容似乎过早结束(也就是说,程序生成的稍后消息不存在)。第三方日志记录工具 (Gibraltar Loupe) 的输出告诉我,如果网络故障导致输出文件暂时不可用,调用 Console.WriteLine 可能会失败,从而导致未处理的异常。
(曾经,普通应用程序的正常异常处理——有点显着——能够写入有关 Console.WriteLine 由于 "The specified network name is no longer available" 而失败时导致的未处理异常的消息——那必须是一个非常暂时的故障!)
除了将对 Console.WriteLine 的所有调用替换为对我自己捕获此类错误的调用、等待网络再次可用并重试之外,我想不出其他方法。 (或者它可以将 运行 剩余部分的输出重定向到本地文件,但如果网络不可用,其他事情可能会失败。)
将应用中对 Console.WriteLine 的所有调用替换为数百个调用将导致重大的源代码更改爆炸式增长,迫使许多月未更改的文件发生更改。我有选择吗?
有没有人对如何处理这个问题有不同的建议(除了从项目开始就抽象掉 Console.WriteLine)?
感谢您的任何建议。
尝试在软件中解决不稳定的硬件问题并不是最好的主意。但请考虑:
- 重定向到本地文件,使用另一个计划任务移动文件。
- 编写一个使用 Process.Start() 启动此应用程序的小守卫应用程序。并使用 Process.ExitCode 来查看它的表现。它可以重新启动应用程序,必要时多次,每次尝试之间的延迟时间更长。
- 使用您自己派生的 TextWriter class 重新分配 Console.Error 和 Console.Out。覆盖 Write(char) 并调用原始 Error/Out.Write(char) 方法,包装在 try/catch 中。尝试多次失败,尝试之间的延迟时间更长。
你可能认为最后一个很吸引人。示例代码:
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...
}
}
老实说,我认为抽象掉 Console.WriteLine 正是您想要做的。它将允许您构建异常处理和重试策略,或者允许您的应用程序在文件再次可用时继续处理它应该做的任何其他事情。它还有助于单元测试和抽象等。
不过,话说回来。您可以在执行任务期间写入本地文件,然后将该文件移动到网络共享。这意味着你应该能够 "trust" Console.WriteLine 将停止工作,这应该避免包装每个调用的需要。然后在任务结束时,您可以将文件移动到您的网络位置。您可以将此移动逻辑包装在一大堆错误处理和重试逻辑中,这不会影响您现有的代码。
我编写了一个控制台应用程序,通常 运行 通过任务计划程序在没有用户存在的情况下进行。如果合适,它将控制台输出重定向到恰好在网络上的文件(名称中带有应用程序启动时间戳)。
我见过一些情况——它们很少见——文件内容似乎过早结束(也就是说,程序生成的稍后消息不存在)。第三方日志记录工具 (Gibraltar Loupe) 的输出告诉我,如果网络故障导致输出文件暂时不可用,调用 Console.WriteLine 可能会失败,从而导致未处理的异常。
(曾经,普通应用程序的正常异常处理——有点显着——能够写入有关 Console.WriteLine 由于 "The specified network name is no longer available" 而失败时导致的未处理异常的消息——那必须是一个非常暂时的故障!)
除了将对 Console.WriteLine 的所有调用替换为对我自己捕获此类错误的调用、等待网络再次可用并重试之外,我想不出其他方法。 (或者它可以将 运行 剩余部分的输出重定向到本地文件,但如果网络不可用,其他事情可能会失败。)
将应用中对 Console.WriteLine 的所有调用替换为数百个调用将导致重大的源代码更改爆炸式增长,迫使许多月未更改的文件发生更改。我有选择吗?
有没有人对如何处理这个问题有不同的建议(除了从项目开始就抽象掉 Console.WriteLine)?
感谢您的任何建议。
尝试在软件中解决不稳定的硬件问题并不是最好的主意。但请考虑:
- 重定向到本地文件,使用另一个计划任务移动文件。
- 编写一个使用 Process.Start() 启动此应用程序的小守卫应用程序。并使用 Process.ExitCode 来查看它的表现。它可以重新启动应用程序,必要时多次,每次尝试之间的延迟时间更长。
- 使用您自己派生的 TextWriter class 重新分配 Console.Error 和 Console.Out。覆盖 Write(char) 并调用原始 Error/Out.Write(char) 方法,包装在 try/catch 中。尝试多次失败,尝试之间的延迟时间更长。
你可能认为最后一个很吸引人。示例代码:
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...
}
}
老实说,我认为抽象掉 Console.WriteLine 正是您想要做的。它将允许您构建异常处理和重试策略,或者允许您的应用程序在文件再次可用时继续处理它应该做的任何其他事情。它还有助于单元测试和抽象等。
不过,话说回来。您可以在执行任务期间写入本地文件,然后将该文件移动到网络共享。这意味着你应该能够 "trust" Console.WriteLine 将停止工作,这应该避免包装每个调用的需要。然后在任务结束时,您可以将文件移动到您的网络位置。您可以将此移动逻辑包装在一大堆错误处理和重试逻辑中,这不会影响您现有的代码。