zoukankan      html  css  js  c++  java
  • Windows 服务 程序开发之异常日志

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

     

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

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

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

    程序大致是这样的

    Windows服务程序大致如下

    代码
    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处理死循环当中,系统的工作日志如下

    代码

    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 - ==================================================

     

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

    代码
    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

  • 相关阅读:
    ajax代码及简单封装
    web开发中不同设备浏览器的区分
    JS实现带复选框的下拉菜单
    常用浏览器的编码设置
    PHP实现实现数字补零格式化
    Linux杂碎2/SHELL
    OS
    Linux sudoers
    代理缓存服务器squid
    es6
  • 原文地址:https://www.cnblogs.com/zycblog/p/1913960.html
Copyright © 2011-2022 走看看