mirror of https://github.com/dapr/dotnet-sdk.git
Adds an option to set a timeout for service invocation (#1252)
* Adds http timeout Signed-off-by: Elena Kolevska <elena@kolevska.com> * Adds a timeout for the grpc client Signed-off-by: Elena Kolevska <elena@kolevska.com> * Small updates Signed-off-by: Elena Kolevska <elena@kolevska.com> * Updates test Signed-off-by: Elena Kolevska <elena@kolevska.com> * Adds a timeout example in docs Signed-off-by: Elena Kolevska <elena@kolevska.com> * Adds e2e test for http service invocation Signed-off-by: Elena Kolevska <elena@kolevska.com> * Adds tests for grpc service invocation Signed-off-by: Elena Kolevska <elena@kolevska.com> * Removes grpc timeout, because it’s not needed. It can be passed directly to the call as shown in the updated tests and docs Signed-off-by: Elena Kolevska <elena@kolevska.com> * Update src/Dapr.Client/DaprClientBuilder.cs Signed-off-by: Elena Kolevska <elena-kolevska@users.noreply.github.com> --------- Signed-off-by: Elena Kolevska <elena@kolevska.com> Signed-off-by: Elena Kolevska <elena-kolevska@users.noreply.github.com> Co-authored-by: Phillip Hoff <phillip@orst.edu>
This commit is contained in:
parent
31af35b6c6
commit
bdca3b320b
|
@ -21,13 +21,16 @@ The .NET SDK allows you to interface with all of the [Dapr building blocks]({{<
|
|||
|
||||
### Invoke a service
|
||||
|
||||
#### HTTP
|
||||
You can either use the `DaprClient` or `System.Net.Http.HttpClient` to invoke your services.
|
||||
|
||||
{{< tabs SDK HTTP>}}
|
||||
|
||||
{{% codetab %}}
|
||||
```csharp
|
||||
using var client = new DaprClientBuilder().Build();
|
||||
using var client = new DaprClientBuilder().
|
||||
UseTimeout(TimeSpan.FromSeconds(2)). // Optionally, set a timeout
|
||||
Build();
|
||||
|
||||
// Invokes a POST method named "deposit" that takes input of type "Transaction"
|
||||
var data = new { id = "17", amount = 99m };
|
||||
|
@ -40,15 +43,33 @@ Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance)
|
|||
```csharp
|
||||
var client = DaprClient.CreateInvokeHttpClient(appId: "routing");
|
||||
|
||||
// To set a timeout on the HTTP client:
|
||||
client.Timeout = TimeSpan.FromSeconds(2);
|
||||
|
||||
var deposit = new Transaction { Id = "17", Amount = 99m };
|
||||
var response = await client.PostAsJsonAsync("/deposit", deposit, cancellationToken);
|
||||
var account = await response.Content.ReadFromJsonAsync<Account>(cancellationToken: cancellationToken);
|
||||
Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
|
||||
```
|
||||
{{% /codetab %}}
|
||||
|
||||
{{< /tabs >}}
|
||||
|
||||
#### gRPC
|
||||
You can use the `DaprClient` to invoke your services over gRPC.
|
||||
{{% codetab %}}
|
||||
```csharp
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
|
||||
var invoker = DaprClient.CreateInvocationInvoker(appId: myAppId, daprEndpoint: serviceEndpoint);
|
||||
var client = new MyService.MyServiceClient(invoker);
|
||||
|
||||
var options = new CallOptions(cancellationToken: cts.Token, deadline: DateTime.UtcNow.AddSeconds(1));
|
||||
await client.MyMethodAsync(new Empty(), options);
|
||||
|
||||
Assert.Equal(StatusCode.DeadlineExceeded, ex.StatusCode);
|
||||
```
|
||||
{{% /codetab %}}
|
||||
|
||||
|
||||
- For a full guide on service invocation visit [How-To: Invoke a service]({{< ref howto-invoke-discover-services.md >}}).
|
||||
|
||||
### Save & get application state
|
||||
|
|
|
@ -57,6 +57,7 @@ namespace Dapr.Client
|
|||
// property exposed for testing purposes
|
||||
internal GrpcChannelOptions GrpcChannelOptions { get; private set; }
|
||||
internal string DaprApiToken { get; private set; }
|
||||
internal TimeSpan Timeout { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the HTTP endpoint used by <see cref="DaprClient" /> for communicating with the Dapr runtime.
|
||||
|
@ -136,6 +137,17 @@ namespace Dapr.Client
|
|||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the timeout for the HTTP client used by the <see cref="DaprClient" />.
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public DaprClientBuilder UseTimeout(TimeSpan timeout)
|
||||
{
|
||||
this.Timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a <see cref="DaprClient" /> instance from the properties of the builder.
|
||||
/// </summary>
|
||||
|
@ -162,9 +174,16 @@ namespace Dapr.Client
|
|||
|
||||
var channel = GrpcChannel.ForAddress(this.GrpcEndpoint, this.GrpcChannelOptions);
|
||||
var client = new Autogenerated.Dapr.DaprClient(channel);
|
||||
|
||||
|
||||
|
||||
var apiTokenHeader = DaprClient.GetDaprApiTokenHeader(this.DaprApiToken);
|
||||
var httpClient = HttpClientFactory is object ? HttpClientFactory() : new HttpClient();
|
||||
|
||||
if (this.Timeout > TimeSpan.Zero)
|
||||
{
|
||||
httpClient.Timeout = this.Timeout;
|
||||
}
|
||||
|
||||
return new DaprClientGrpc(channel, client, httpClient, httpEndpoint, this.JsonSerializerOptions, apiTokenHeader);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
using System;
|
||||
using System.Text.Json;
|
||||
using Dapr.Client;
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
using Xunit;
|
||||
|
||||
|
@ -110,5 +111,15 @@ namespace Dapr.AspNetCore.Test
|
|||
var entry = DaprClient.GetDaprApiTokenHeader(builder.DaprApiToken);
|
||||
Assert.Equal(default, entry);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DaprClientBuilder_SetsTimeout()
|
||||
{
|
||||
var builder = new DaprClientBuilder();
|
||||
builder.UseTimeout(TimeSpan.FromSeconds(2));
|
||||
builder.Build();
|
||||
Assert.Equal(2, builder.Timeout.Seconds);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ service Messager {
|
|||
rpc GetMessage(GetMessageRequest) returns (MessageResponse);
|
||||
// Send a series of broadcast messages.
|
||||
rpc StreamBroadcast(stream Broadcast) returns (stream MessageResponse);
|
||||
rpc DelayedResponse(google.protobuf.Empty) returns (google.protobuf.Empty);
|
||||
}
|
||||
|
||||
message SendMessageRequest {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Grpc.Core;
|
||||
|
@ -44,5 +45,11 @@ namespace Dapr.E2E.Test
|
|||
await responseStream.WriteAsync(new MessageResponse { Message = request.Message });
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Empty> DelayedResponse(Empty request, ServerCallContext context)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(2));
|
||||
return new Empty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,5 +65,14 @@ namespace Dapr.E2E.Test
|
|||
};
|
||||
return account;
|
||||
}
|
||||
|
||||
[Authorize("Dapr")]
|
||||
[HttpGet("DelayedResponse")]
|
||||
public async Task<IActionResult> DelayedResponse()
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(2));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ using System;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Client;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Grpc.Core;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
@ -77,5 +78,21 @@ namespace Dapr.E2E.Test
|
|||
await responseTask;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestGrpcServiceInvocationWithTimeout()
|
||||
{
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
|
||||
var invoker = DaprClient.CreateInvocationInvoker(appId: this.AppId, daprEndpoint: this.GrpcEndpoint);
|
||||
var client = new Messager.MessagerClient(invoker);
|
||||
|
||||
var options = new CallOptions(cancellationToken: cts.Token, deadline: DateTime.UtcNow.AddSeconds(1));
|
||||
var ex = await Assert.ThrowsAsync<RpcException>(async () =>
|
||||
{
|
||||
await client.DelayedResponseAsync(new Empty(), options);
|
||||
});
|
||||
|
||||
Assert.Equal(StatusCode.DeadlineExceeded, ex.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,10 +13,15 @@
|
|||
namespace Dapr.E2E.Test
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Client;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Grpc.Core;
|
||||
using Xunit;
|
||||
|
||||
public partial class E2ETests
|
||||
|
@ -58,6 +63,25 @@ namespace Dapr.E2E.Test
|
|||
Assert.Equal("1", account.Id);
|
||||
Assert.Equal(150, account.Balance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestHttpServiceInvocationWithTimeout()
|
||||
{
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
|
||||
using var client = new DaprClientBuilder()
|
||||
.UseHttpEndpoint(this.HttpEndpoint)
|
||||
.UseTimeout(TimeSpan.FromSeconds(1))
|
||||
.Build();
|
||||
|
||||
await Assert.ThrowsAsync<TaskCanceledException>(async () =>
|
||||
{
|
||||
await client.InvokeMethodAsync<HttpResponseMessage>(
|
||||
appId: this.AppId,
|
||||
methodName: "DelayedResponse",
|
||||
httpMethod: new HttpMethod("GET"),
|
||||
cancellationToken: cts.Token);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal class Transaction
|
||||
|
|
Loading…
Reference in New Issue