如果你的packages在执行的过程中有没有被捕获到的异常,则sqldumper会跳出来获取这些异常信息输出,存在下面的目录中:
C:\Program Files\Microsoft SQL Server\110\Shared\ErrorDumps
文件有以.tmp和mdmp结尾.
SQLDUMPER_ERRORLOG.log
通常这个时候整个package就会被hang住,如果你使用Dtsdebughost.exe(即在VS)中测试时,
如果你直接使用dtexec.exe来操作,可能dtexec就已经崩溃了.stop working.
我的包中使用到了多线程进行数据加载,如果线程中出现了异常,package会在测试时hang住,所以我就进行了下面的测试.
我在Package中使用了一个scripttask,new 了三个线程执行一些简单的测试操作.
我特意让子线程抛出一些测试异常,我们在主线程中无法捕获这些子线程抛出的异常.
但是我使用appdomain.currentdomain.unhandleexception方法来捕获处理这些异常.
第一次测试的结果是:
sqldumper跳出来,然后pacakge就一直running,SSDT中显示包已经执行完成.但是其onPostExecute事件并未被执行.
从processinginfo中可以看到unhandleexception绑定的事件处理方法已经执行了.
界面中一直hang住的情况,我分析是有些线程没有被中止
然后我就开始了第二次尝试,
在处理未捕获异常的事件处理方法中加入处理线程的方法,我让每一个线程在启动前都加入一个list<thread>对象.
处理的时候,先捕获异常信息,然后输出线程的状态,最后abort线程.我发现task顺利完成了.
第三次测试,我在Package的OnQueryCancel中加入一个scriptask,但其中故意生成一个异常,scripttask也会被hang住,
因为我发现在package的执行过程中,onquerycancel事件会被不定期触发,只要我们的System::Cancel变量是false.
在bookonline上查找相关onquercancel的说明,它会不定期触发,你可以通过设置system::cancel变量的值通知它停止运行,它给了你这样的一个机会,终止任务的执行.
我想到了MSDN论坛上有一个人问题的问题,他说如果package的执行时长超过10分钟,就需要它自动停止,其实就可以使用类似这样的方法,如果package执行时长超过10分钟,就把它的System::Cancel值置为true即可.
在package中的代码如下:
bool isreuse = false;
List<Thread> _listworkthreads = new List<Thread>();
object internalsyncobj = new object();
/// <summary>
/// This method is called when this script task executes in the control flow.
/// Before returning from this method, set the value of Dts.TaskResult to indicate success or failure.
/// To open Help, press F1.
/// </summary>
public void Main()
{
// TODO: Add your code here
AppDomain.CurrentDomain.UnhandledException += HandleException; Dts.TaskResult = (int)ScriptResults.Success; string mymsg = "thread :" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()
+ " domainid:"
+ System.Threading.Thread.GetDomainID().ToString()
;
Dts.Events.FireInformation(, "showmsg", mymsg, "", , ref isreuse); int times = ;
bool isused = false;
while (times < )
{
times++;
Dts.Events.FireInformation(, "showmsg", times.ToString(), "", , ref isreuse);
if (times == && !isused)
{
Dts.Events.FireInformation(, "showmsg", "update var_threadcount to 2", "", , ref isreuse);
Dts.Variables["var_threadcount"].Value = ;
//try { Dts.VariableDispenser.Reset(); }catch { }
isused = true;
}
} runNewThread("test"); Thread th = new Thread(
obj =>
{
throw new Exception("hello exception in thread");
});
lock (internalsyncobj) { _listworkthreads.Add(th); }
th.Start(); System.Threading.Thread.Sleep( * );
} void runNewThread(string msg)
{
Thread th = new Thread(
obj =>
{
Dts.Events.FireInformation(, "showmsg", msg, "", , ref isreuse);
string mymsg = "thread :" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()
+ " domainid:"
+ System.Threading.Thread.GetDomainID().ToString()
;
Dts.Events.FireInformation(, "showmsg", mymsg, "", , ref isreuse); Thread t = new Thread(() =>
{
throw new Exception("hello exception in child thread!");
});
lock (internalsyncobj) { _listworkthreads.Add(t); }
t.Start();
}
);
lock (internalsyncobj) { _listworkthreads.Add(th); }
th.Start(msg); } void HandleException(object sender, UnhandledExceptionEventArgs e)
{
Dts.Events.FireInformation(, "UnhandleException",
"sender:" + sender.ToString() +
"message:" + ((Exception)e.ExceptionObject).Message
, "", , ref isreuse); //handle child thread
lock (internalsyncobj)
{
Dts.Events.FireInformation(,"AppdomainUnhandleException", "thread count:" + _listworkthreads.Count.ToString()
+ " start to kill all child thread at time:" + DateTime.Now.ToString()
, "", , ref isreuse);
foreach (Thread th in _listworkthreads)
{
Dts.Events.FireInformation(, "ThreadState", "thread state:" + th.ThreadState.ToString()
+ DateTime.Now.ToString()
, "", , ref isreuse); try {
th.Abort(); }
catch (Exception ex) { }
}
} }