Windows 服务 程序开发之异常日志

Windows 服务 程序开发之异常日志

 

事情概况 昨天Windows服务程序里面的linq to sql 报了个错误,如下

System.Data.Linq.ChangeConflictException: 找不到行或行已更改。”

这个错本身属于并发的问题,可是我这里要说的却是另外一回事。发现这个问题以后,便把服务程序停掉,然后再起动,结果还是一样的,这个错仍然存在,最后把服务程序卸载了,然后再安装一次就没有问题了。这样一个奇怪的问题,写一篇日志把它记录下来,作为教训,服务程序每秒执行一次,一个小小的bug就会引起重大影响,这个问题导致短时间内出现了1000多封拉圾邮件,让邮件服务程序承受不了。

 

程序大致是这样的

Windows服务程序大致如下

ExpandedBlockStart.gif 代码
using  System;
using  System.Data.SqlClient;
using  System.Linq;
using  System.ServiceProcess;
using  System.Timers;

using  log4net;

namespace  Avantouch.Platform.WinServices.Topup
{
    
internal   partial   class  TopupService3 : ServiceBase
    {

        
private   static   readonly  ILog SubmitLog  =  LogManager.GetLogger( " DFSubmitLog " );

        
private   static   readonly  ILog VerifyLog  =  LogManager.GetLogger( " DFVerifyLog " );

        
private   static  PlatformDataContext _submitDataContext;

        
private   static  PlatformDataContext _verifyDataContext;

        
private   static  PlatformDataContext _NewOrderDataContext;

        
private   readonly  Timer _submitTimer;

        
private   readonly  Timer _verifyTimer;

        
#endregion

        
public  TopupService3()
        {
            InitializeComponent();

            _submitDataContext 
=   new  PlatformDataContext(Settings.Default.ServicesConnectionString);
            _verifyDataContext 
=   new  PlatformDataContext(Settings.Default.ServicesConnectionString);
            _submitTimer 
=   new  Timer( 1000 );
            _submitTimer.Elapsed 
+=  SubmitTimerElapsed;

            _verifyTimer 
=   new  Timer( 5   *   60   *   1000 );
            _verifyTimer.Elapsed 
+=  VerifyTimerElapsed;
        }

        
protected   override   void  OnStart( string [] args)
        {
            _submitTimer.Start();

            _verifyTimer.Start();
        }

        
protected   override   void  OnStop()
        {
            _submitTimer.Stop();

            _verifyTimer.Stop();
        }

        
internal   void  SubmitTimerElapsed( object  sender, ElapsedEventArgs e)
        {
            _submitTimer.Stop();
            
try
            {
                IQueryable
< Order >  orders  =  from t  in  _submitDataContext.Orders
                                           join t0 
in  _submitDataContext.Product on t.ProductId equals t0.ProductId
                                           
where  t.CategoryId  ==   1   &&  t0.SupplierId  ==   5   &&  t.Submitted  ==   false   &&  t.Deleted 

==   " 0 "
                                           select t;
                Order record 
=  orders.FirstOrDefault();
                
if  (record  !=   null )
                {
                   
                    
// 处理程序
                    _submitDataContext.SubmitChanges();
                }
            }
            
catch  (SqlException sqlException)
            {
                SubmitLog.Error(
" 数据库错误 " , sqlException);
                Alert(
" 0003 " " 1 " );
            }
            
catch  (Exception exception)
            {
                SubmitLog.Error(
" 异常错误 " , exception);
                Alert(
" 0004 " " 1 " );
            }
            
finally
            {
                _submitTimer.Start();
            }
        }




        
internal   void  VerifyTimerElapsed( object  sender, ElapsedEventArgs e)
        {
            _verifyTimer.Stop();
            VerifyLog.Info(
" -------------------------------------------------- " );
            VerifyLog.InfoFormat(
" 德丰充值查询验证服务时间:{0}信息输出...... " , System.DateTime.Now);
            
try
            {

                IQueryable
< Order >  orders  =  from t  in  _verifyDataContext.Orders
                                           join t0 
in  _verifyDataContext.Product on t.ProductId equals t0.ProductId
                                           
where  t.CategoryId  ==   1   &&  t0.SupplierId  ==   5   &&  t.Submitted  &&   ! t.Verified  &&  

t.Deleted 
==   " 0 "   &&  t.SubmitTime.Value.AddMinutes( 5 <  DateTime.Now
                                           select t;

                
foreach  (Order record  in  orders)
                {
                   
// 处理程序
                     _verifyDataContext.SubmitChanges();
                }
            }
            
catch  (SqlException sqlException)
            {
                
// 邮件
                VerifyLog.Error( " 数据库错误 " , sqlException);
                Alert(
" 0003 " " 2 " );
            }
            
catch  (Exception exception)
            {
                
// TODO:邮件
                VerifyLog.Error( " 异常错误 " , exception);
                Alert(
" 0004 " " 2 " );
            }
            
finally
            {
                _verifyTimer.Start();
            }
        }

 

       

    }
}

 

  

程序里有两个timer,都是查找出记录,处理完了以后再更新,其中_submitTimer是一秒钟更新一次,而_verifyTimer5分钟后再查询记录更新处理,正常情况下两个timer不会同时处理同一条记录,即linq to sql 不会发生并发的问题。但是如果submitTimer里的程序出了异常,延迟了5分钟,异致两个timer会同时处理同一条记录,linq to sql 导致了并发冲突.

结果submitTimer处理死循环当中,系统的工作日志如下

ExpandedBlockStart.gif 代码

2010 - 12 - 21   17 : 27 : 27 , 023  [ 10 ] INFO  DFSubmitLog  -   ==================================================
2010 - 12 - 21   17 : 27 : 27 , 023  [ 10 ] INFO  DFSubmitLog  -  开始提交序号为353770的订单......
2010 - 12 - 21   17 : 27 : 27 , 042  [ 10 ] DEBUG DFSubmitLog  -  数据库字段已更新......
2010 - 12 - 21   17 : 37 : 57 , 792  [ 10 ] ERROR DFSubmitLog  -  异常错误
System.Data.Linq.ChangeConflictException: 找不到行或行已更改。
   在 System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   在 System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
   在 Avantouch.Platform.WinServices.Topup.TopupService3.SubmitTimerElapsed(Object sender, ElapsedEventArgs e)
2010 - 12 - 21   17 : 37 : 57 , 793  [ 10 ] INFO  DFSubmitLog  -  开始下发报警邮件通知......
2010 - 12 - 21   17 : 37 : 57 , 803  [ 10 ] INFO  DFSubmitLog  -  邮件已下发......
2010 - 12 - 21   17 : 37 : 58 , 891  [ 9 ] INFO  DFSubmitLog  -   ==================================================
2010 - 12 - 21   17 : 37 : 58 , 891  [ 9 ] INFO  DFSubmitLog  -  开始提交序号为353773的订单......
2010 - 12 - 21   17 : 37 : 58 , 909  [ 9 ] ERROR DFSubmitLog  -  异常错误
System.Data.Linq.ChangeConflictException: 找不到行或行已更改。
   在 System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   在 System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
   在 Avantouch.Platform.WinServices.Topup.TopupService3.SubmitTimerElapsed(Object sender, ElapsedEventArgs e)
2010 - 12 - 21   17 : 37 : 58 , 910  [ 9 ] INFO  DFSubmitLog  -  开始下发报警邮件通知......
2010 - 12 - 21   17 : 37 : 58 , 919  [ 9 ] INFO  DFSubmitLog  -  邮件已下发......
2010 - 12 - 21   17 : 38 : 00 , 013  [ 9 ] INFO  DFSubmitLog  -   ==================================================
2010 - 12 - 21   17 : 38 : 00 , 013  [ 9 ] INFO  DFSubmitLog  -  开始提交序号为353773的订单......
2010 - 12 - 21   17 : 38 : 00 , 036  [ 9 ] ERROR DFSubmitLog  -  异常错误
System.Data.Linq.ChangeConflictException: 找不到行或行已更改。
   在 System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   在 System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
   在 Avantouch.Platform.WinServices.Topup.TopupService3.SubmitTimerElapsed(Object sender, ElapsedEventArgs e)
2010 - 12 - 21   17 : 38 : 00 , 036  [ 9 ] INFO  DFSubmitLog  -  开始下发报警邮件通知......
2010 - 12 - 21   17 : 38 : 00 , 041  [ 9 ] INFO  DFSubmitLog  -  邮件已下发......
2010 - 12 - 21   17 : 38 : 01 , 121  [ 9 ] INFO  DFSubmitLog  -   ==================================================
2010 - 12 - 21   17 : 38 : 01 , 121  [ 9 ] INFO  DFSubmitLog  -  开始提交序号为353773的订单......
2010 - 12 - 21   17 : 38 : 01 , 140  [ 9 ] ERROR DFSubmitLog  -  异常错误
System.Data.Linq.ChangeConflictException: 找不到行或行已更改。
   在 System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   在 System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
   在 Avantouch.Platform.WinServices.Topup.TopupService3.SubmitTimerElapsed(Object sender, ElapsedEventArgs e)
2010 - 12 - 21   17 : 38 : 01 , 140  [ 9 ] INFO  DFSubmitLog  -  开始下发报警邮件通知......
2010 - 12 - 21   17 : 38 : 01 , 146  [ 9 ] INFO  DFSubmitLog  -  邮件已下发......
2010 - 12 - 21   17 : 38 : 02 , 230  [ 9 ] INFO  DFSubmitLog  -   ==================================================

 

 

 

这是这样一直处于死循环当中了。这时候把服务停了,然后启动,还是出错,日志记录如下

 

ExpandedBlockStart.gif 代码
2010 - 12 - 21   18 : 04 : 27 , 848  [ 8 ] INFO  DFSubmitLog  -  服务已停止......
2010 - 12 - 21   18 : 04 : 29 , 156  [ 9 ] INFO  DFSubmitLog  -  服务已启动......
2010 - 12 - 21   18 : 04 : 30 , 241  [ 9 ] INFO  DFSubmitLog  -   ==================================================
2010 - 12 - 21   18 : 04 : 30 , 241  [ 9 ] INFO  DFSubmitLog  -  开始提交序号为353773的订单......
2010 - 12 - 21   18 : 04 : 30 , 261  [ 9 ] ERROR DFSubmitLog  -  异常错误
System.Data.Linq.ChangeConflictException: 找不到行或行已更改。
   在 System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   在 System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
   在 Avantouch.Platform.WinServices.Topup.TopupService3.SubmitTimerElapsed(Object sender, ElapsedEventArgs e)
2010 - 12 - 21   18 : 04 : 30 , 262  [ 9 ] INFO  DFSubmitLog  -  开始下发报警邮件通知......
2010 - 12 - 21   18 : 04 : 30 , 268  [ 9 ] INFO  DFSubmitLog  -  邮件已下发......
2010 - 12 - 21   18 : 04 : 31 , 351  [ 9 ] INFO  DFSubmitLog  -   ==================================================
2010 - 12 - 21   18 : 04 : 31 , 351  [ 9 ] INFO  DFSubmitLog  -  开始提交序号为353773的订单......
2010 - 12 - 21   18 : 04 : 31 , 371  [ 9 ] ERROR DFSubmitLog  -  异常错误
System.Data.Linq.ChangeConflictException: 找不到行或行已更改。
   在 System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   在 System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
   在 Avantouch.Platform.WinServices.Topup.TopupService3.SubmitTimerElapsed(Object sender, ElapsedEventArgs e)
2010 - 12 - 21   18 : 04 : 31 , 372  [ 9 ] INFO  DFSubmitLog  -  开始下发报警邮件通知......
2010 - 12 - 21   18 : 04 : 31 , 378  [ 9 ] INFO  DFSubmitLog  -  邮件已下发......
2010 - 12 - 21   18 : 04 : 32 , 474  [ 6 ] INFO  DFSubmitLog  -   ==================================================

 

 

 

结果把服务卸载了,然后再安装问题便没了.遇到这个问题,然后网上查了一下,也咨询了一相,只能考虑linq to sql 的资源没有释放掉了。这个问题的根源在于submitTimer里的异常,导致两个timer同时处理一条记录,目前先处理掉这个根源问题

 

有关linq to sql 的资源释放问是,可参考以下链接的文章

http://www.cnblogs.com/kirinboy/archive/2010/01/04/dispose-datacontext-or-not.html

http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/10/19/linq-to-sql-connection-issue.aspx

有关解决linq to sql 并发冲突的话,可参考以下文章

http://www.cnblogs.com/sunnyfong/archive/2008/09/25/1298829.html

 

 

 

转载于:https://www.cnblogs.com/zycblog/archive/2010/12/22/1913960.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值