【问题标题】:Timeout Notification for Asynchronous Request异步请求超时通知
【发布时间】:2014-01-08 12:52:56
【问题描述】:

我正在将 SPARQL 查询作为异步请求发送到 SPARQL 端点,目前使用 dotNetRDF libraryDBpedia。虽然更简单的查询通常有效,但更复杂的查询有时会导致超时。

我正在寻找一种方法来处理超时,方法是在它们发生时捕获一些事件。

我使用SparqlRemoteEndpoint class 中的one of the asynchronous QueryWithResultSet overloads 发送查询。

SparqlResultsCallback 所述,如果异步请求失败,state 对象将被替换为 AsyncError instance。这确实表明存在超时,但它似乎仅在请求发送后 10 分钟 才这样做。例如,当我的超时时间是 30 秒时,我想在 30 秒后知道请求是否成功。 (35 秒也可以,但你明白了。)

这是一个示例应用程序,它发送两个请求,第一个非常简单,很可能在超时(这里设置为 120 秒)内成功,而第二个相当复杂,很容易在 DBpedia 上失败:

using System;
using System.Collections.Concurrent;

using VDS.RDF;
using VDS.RDF.Query;

public class TestTimeout
{
    private static string FormatResults(SparqlResultSet results, object state)
    {
        var result = new System.Text.StringBuilder();

        result.AppendLine(DateTime.Now.ToLongTimeString());

        var asyncError = state as AsyncError;
        if (asyncError != null) {
            result.AppendLine(asyncError.State.ToString());
            result.AppendLine(asyncError.Error.ToString());
        } else {
            result.AppendLine(state.ToString());
        }

        if (results == null) {
            result.AppendLine("results == null");
        } else {
            result.AppendLine("results.Count == " + results.Count.ToString());
        }

        return result.ToString();
    }

    public static void Main(string[] args)
    {
        Console.WriteLine("Launched ...");
        Console.WriteLine(DateTime.Now.ToLongTimeString());

        var output = new BlockingCollection<string>();

        var ep = new SparqlRemoteEndpoint(new Uri("http://dbpedia.org/sparql"));
        ep.Timeout = 120;

        Console.WriteLine("Server == " + ep.Uri.AbsoluteUri);
        Console.WriteLine("HTTP Method == " + ep.HttpMode);
        Console.WriteLine("Timeout == " + ep.Timeout.ToString());

        string query = "SELECT DISTINCT ?a\n"
            + "WHERE {\n"
            + "  ?a <http://www.w3.org/2000/01/rdf-schema#label> ?b.\n"
            + "}\n"
            + "LIMIT 10\n";

        ep.QueryWithResultSet(query,
            (results, state) => {
                output.Add(FormatResults(results, state));
            },
            "Query 1");

        query = "SELECT DISTINCT ?v5 ?v8\n"
            + "WHERE {\n"
            + "  {\n"
            + "    SELECT DISTINCT ?v5\n"
            + "    WHERE {\n"
            + "      ?v6 ?v5 ?v7.\n"
            + "      FILTER(regex(str(?v5), \"[/#]c[^/#]*$\", \"i\")).\n"
            + "    }\n"
            + "    OFFSET 0\n"
            + "    LIMIT 20\n"
            + "  }.\n"
            + "  OPTIONAL {\n"
            + "    ?v5 <http://www.w3.org/2000/01/rdf-schema#label> ?v8.\n"
            + "    FILTER(lang(?v8) = \"en\").\n"
            + "  }.\n"
            + "}\n"
            + "ORDER BY str(?v5)\n";

        ep.QueryWithResultSet(query,
            (results, state) => {
                output.Add(FormatResults(results, state));
            },
            "Query 2");

        Console.WriteLine("Queries sent.");
        Console.WriteLine(DateTime.Now.ToLongTimeString());
        Console.WriteLine();

        string result = output.Take();
        Console.WriteLine(result);

        result = output.Take();
        Console.WriteLine(result);

        Console.ReadLine();
    }
}

当我运行它时,我可以重现地得到如下输出:

13:13:23
Server == http://dbpedia.org/sparql
HTTP Method == GET
Timeout == 120
Queries sent.
13:13:25

13:13:25
Query 1
results.Count == 10

13:23:25
Query 2
VDS.RDF.Query.RdfQueryException: A HTTP error occurred while making an asynchron
ous query, see inner exception for details ---> System.Net.WebException: Der Rem
oteserver hat einen Fehler zurückgegeben: (504) Gatewaytimeout.
   bei System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   bei VDS.RDF.Query.SparqlRemoteEndpoint.<>c__DisplayClass13.<QueryWithResultSe
t>b__11(IAsyncResult innerResult)
   --- Ende der internen Ausnahmestapelüberwachung ---
results == null

显然,确切的时间会有所不同,但关键是在请求发送后大约 10 分钟 收到基于第二个查询的错误消息,与设置的 2 分钟相差甚远超时。

我是不是在这里错误地使用了 dotNetRDF,还是故意让我必须运行一个额外的计时器来自己测量超时并自行做出反应,除非同时收到任何响应?

【问题讨论】:

  • 顺便说一句,Timeout 属性应该以毫秒而不是秒为单位设置,这在当前 API 文档中不够清楚,并且这已经由另一个用户报告并在中继中修复

标签: timeout sparql dbpedia dotnetrdf


【解决方案1】:

不,您没有错误地使用 dotNetRDF,而是似乎存在一个错误,即在异步运行查询时,端点上设置的超时不会得到遵守。这已被归档为CORE-393

顺便说一句,即使修复了这个错误,您也不一定会在设置的超时时遇到硬超时。本质上是您为SparqlRemoteEndpoint 实例的Timeout 属性设置的值,该值用于设置.Net HttpWebRequestTimeout 属性。 HttpWebRequest.Timeout 的文档说明如下:

获取或设置 GetResponse 的超时值(以毫秒为单位) 和 GetRequestStream 方法。

因此,您可以等待超时以连接到POST 查询,然后再次超时以开始接收响应。一旦您开始接收响应,超时就变得无关紧要,并且不会被处理响应的代码遵守。

因此,如果你想要一个硬超时,你最好自己实现它,从长远来看,这可能是我们可以添加到 dotNetRDF 的东西,但这实现起来更复杂,只需修复关于超时不被 HTTP 尊重的错误请求。

【讨论】:

  • 这个bug现在应该已经默认修复了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多