在异步调用上等待会引发意外的超时异常

时间:2019-03-01 15:18:56

标签: c# asynchronous azure-service-fabric

我正在Service Fabric应用程序上执行一系列异步调用,并且有一个长时间运行的调用,它将在5-10分钟后引发TimeoutException。 我的代码与此类似:

System.AggregateException: One or more errors occurred. ---> System.TimeoutException: This can happen if message is dropped when service is busy or its long running operation and taking more time than configured Operation Timeout.

at Microsoft.ServiceFabric.Services.Communication.Client.ServicePartitionClient`1.<InvokeWithRetryAsync>d__24`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.ServiceFabric.Services.Remoting.V1.Client.ServiceRemotingPartitionClient.<InvokeAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.ServiceFabric.Services.Remoting.Builder.ProxyBase.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.ServiceFabric.Services.Remoting.Builder.ProxyBase.<ContinueWithResult>d__16`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at RestoreService.<RestoreAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at RestoreWorker.<ExecuteAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at Listener.<HandleRequestAsync>d__15.MoveNext()

如果方法UpdateTheDBAsync需要很长时间才能执行,我将收到TimeoutException

@ Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (data.getData()!=null) {
        videoUri = data.getData();


        if (resultCode == RESULT_OK) {
            if (requestCode == REQUEST_VIDEO) {
                Toast.makeText(this, data.getData().toString(), Toast.LENGTH_LONG).show();

            } else if (requestCode == VIDEO_RECORD_REQUEST) {
                videoUri = data.getData();
                Toast.makeText(this, data.getData().toString(), Toast.LENGTH_LONG).show();
            }
        }
    }
    else
    {
        Toast.makeText(this, "No file", Toast.LENGTH_SHORT).show();
    }

}

即使未配置超时,为什么仍会超时?我究竟做错了什么? 任何帮助表示赞赏。

PS:这与以前使用的代码完全相同

1 个答案:

答案 0 :(得分:0)

问题与服务之间的远程处理(ServiceFabric.Services.Remoting)的默认超时5分钟有关。

远程处理的版本2可用,并且根据Microsoft documentation“远程处理V2堆栈的性能更好”。

升级到V2后,解决问题的一种可能方法是增加超时时间

 new ServiceProxyFactory((c) => new FabricTransportServiceRemotingClientFactory(
                                       new FabricTransportRemotingSettings() {
                                           OperationTimeout = TimeSpan.FromMinutes(30)
                                       })))

但这只会增加超时,而不能将其完全删除。

解决该问题的另一种方法是启动一个直接在与远程处理一起使用的服务中处理的工作程序,然后等待其完成。 这样,解决方案就不受远程超时的约束。

例如:

替换此:

await restoreClient.RestoreAsync(id, name).ConfigureAwait(false);

var workerId = StartANewWorker()
JobState jobState;
do {
    //poll for the status of the new worker
    var workerStatus = GetStatusOfTheWorker(workerId);

    await Task.Delay(1000).ConfigureAwait(false);
    if (workerStatus == Failed) {
        throw new Exception("Something went wrong");
    }
} while (workerStatus != Finished);