【问题标题】:Duplicate entries on server response .net服务器响应.net上的重复条目
【发布时间】:2014-05-30 13:46:27
【问题描述】:

场景

一个 Windows 服务每两分钟轮询一次 url 以检索某些数据。

如果自上次调用以来添加了任何数据,则检索并存储数据,否则循环继续。

问题

有时一个请求需要超过两分钟才能返回响应。

发生这种情况时,仍会发出下一个请求并查找新数据,因为上一个请求尚未返回响应

这会导致存储数据时出现重复条目​​。

我尝试过的

我试图通过使用像这样的布尔值来处理这个问题:

Boolean InProgress = true;
foreach (var item in Lists)
{ 
\\Make a request and return new data (if any)
InProgress = false;
if (InProgress = false)
  {
  \\Store new data
  }
}

这并不能解决问题。我相信我在错误的地方使用了布尔值,但我不确定它应该在哪里。

这是发出请求并存储数据的循环

void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        try
        {
            Data getCredentials = new Data();
            DataTable credentials = getCredentials.loadCredentials();
            Boolean InProgress = true;

            for (int i = 0; i < credentials.Rows.Count; i++)
            {
                if (credentials != null)
                {
                    var PBranchID = (int)credentials.Rows[i]["PortalBranchID"];
                    var negRef = (int)credentials.Rows[i]["NegotiatorRef"];
                    var Username = credentials.Rows[i]["Username"].ToString();
                    var Password = credentials.Rows[i]["Password"].ToString();
                    var Domain = credentials.Rows[i]["Domain"].ToString();
                    var FooCompanyBaseUrl = "https://" + Domain + ".FooCompany.com/";

                    Data getCalls = new Data();
                    DataTable calls = getCalls.loadCalls(PBranchID);

                    //If it's not the first call
                    if (calls != null && calls.Rows.Count > 0)
                    {
                        //Makes a call
                        DateTime CreatedSince = DateTime.SpecifyKind((DateTime)calls.Rows[0]["LastSuccessOn"], DateTimeKind.Local);
                        string IssueListUrl = FooCompany.WebApi.V2.URLs.Issues(BaseUrl, null, CreatedSince.ToUniversalTime(), null);
                        FooCompany.WebApi.V2.DTO.PrevNextPagedList resultIssueList;

                        resultIssueList = FooCompany.WebApi.Client.Helper.Utils.Getter<Foocompany.WebApi.V2.DTO.PrevNextPagedList>(IssueListUrl, Username, Password);
                        InProgress = false;
                        if (InProgress == false)
                        {
                            if (resultIssueList.Items.Count > 0)
                            {
                                //If call returns new issues, save call
                                Data saveCalls = new Data();
                                saveCalls.saveCalls(PBranchID);

                                foreach (var item in resultIssueList.Items)
                                {
                                    var Issue = FooCompany.WebApi.Client.Helper.Utils.Getter<FooCompany.WebApi.V2.DTO.Issue>(item, Username, Password);

                                    string TenantSurname = Issue.Surname;
                                    string TenantEmail = Issue.EmailAddress;
                                    Data tenants = new Data();
                                    int tenantPropRef = Convert.ToInt32(tenants.loadTenantPropRef(PBranchID, TenantSurname, TenantEmail));
                                    Data Properties = new Data();
                                    DataTable propAddress = Properties.loadPropAddress(PBranchID, tenantPropRef);
                                    var Address1 = propAddress.Rows[0]["Address1"];
                                    var Address2 = propAddress.Rows[0]["Address2"];
                                    var AddressFolder = Address1 + "," + Address2;
                                    if (!Directory.Exists("path"))
                                    {
                                        Directory.CreateDirectory("path");
                                    }
                                    string ReportPDFDestination = "path";

                                    if (File.Exists(ReportPDFDestination))
                                    {
                                        File.Delete(ReportPDFDestination);
                                    }
                                    FooCompany.WebApi.Client.Helper.Utils.DownloadFileAuthenticated(FooCompany.WebApi.V2.URLs.IssueReport(BaseUrl, Issue.Id), Username, Password, ReportPDFDestination);


                                    //Store data 

                                }
                                IssueListUrl = resultIssueList.NextURL;

                            }
                        }

                }
                else
                {
                    continue;
                }
            }

        }


        catch (Exception ex)
        {
            //write to log
        }
    }

问题

我确信有比布尔值更好的方法。

谁能建议一种不同的方法来正确处理这个问题? 谢谢。

解决方案

我最终结合了 Thomas 和 Mason 的建议。我在我的 Windows 服务的主要功能周围包裹了一个锁定语句,并在调用远程服务器的函数部分中使用了一个布尔值。 经过多次测试,没有错误。

【问题讨论】:

  • 我们需要查看调用此代码的您的代码,以便给您一个良好的响应。
  • 我使用线程,但我会跟踪标志中的状态,并且在标志重置为零或超过合理时间之前,我不允许它再次调用。
  • @mason 我已经添加了调用的代码
  • @dura 添加同步是否解决了您的问题?
  • 您添加了实际检索数据的代码,但这并不真正相关。我们需要看看你发布的第一个代码是什么。顺便说一句,第一个块,您将布尔值设置为假,然后测试它是否为假。它总是是假的。您需要使用== 来测试是否相等。 = 是赋值运算符。

标签: c# service windows-services locking boolean


【解决方案1】:

您似乎遇到了同步问题,只需将遍历 List 的代码用锁包围,就可以了。

public class MyClass{
private readonly object internalLock= new object();
private bool AlreadyRunning { get;  set; }
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
    if(AlreadyRunning){
        return;
    }

    try{
        lock(internalLock){     
            Thread.MemoryBarrier();

            if(AlreadyRunning){
                return;
            }
            AlreadyRunning = true;

            ...Do all the things...
        }
    }
    catch(Exception e){
        ..Exception handling
    }
    finally
    {
        AlreadyRunning = false;
    }
}

【讨论】:

  • 发出请求的行需要在循环内。所以我不确定是否将代码锁定在其中。
  • @dura 你需要给我们更多的代码。您似乎有同步问题。现在,您可以尝试自己寻找或给我们更多代码!
  • 抱歉,我做了一场噩梦,要从代码中删除敏感信息。但我现在已经添加了。
  • 在此期间我将尝试锁定解决方案。
  • 您能否确认您的问题是您为同一个问题生成了多个ReportPDFDestination
【解决方案2】:
bool InProgress=false;

void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
    if(!InProgress)
        {
        InProgress=true;
        //retrieve data
        InProgress=false;
        }
    }

您的 InProgress 变量需要在事件处理程序之外声明。当您输入该方法时,请检查它是否已在运行。如果是,那么我们什么也不做。如果它没有运行,那么我们说它正在运行,检索我们的数据,然后重置我们的标志,说我们已经完成了运行。

您可能需要为线程安全添加适当的锁,类似于 Thomas 的回答。

【讨论】:

  • 谢谢,很清楚。我会等着标记我的答案,看看我最终会使用哪一个。
  • 小心,如果抛出异常,那么您将停止检索数据,因为InProgress 将保持false。我认为 try/catch/finally 很重要。
  • @Mason 非常感谢您抽出宝贵时间。我已将 Thomas 标记为答案,因为他在聊天中花了一些额外的时间为我提供建议(而且他的票数也比你少)
猜你喜欢
  • 1970-01-01
  • 2020-10-20
  • 2013-01-08
  • 1970-01-01
  • 2018-03-10
  • 1970-01-01
  • 2019-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多