diff --git a/Client.UnitTests/GatewayTestService.cs b/Client.UnitTests/GatewayTestService.cs index 66155df4..fe399b6c 100644 --- a/Client.UnitTests/GatewayTestService.cs +++ b/Client.UnitTests/GatewayTestService.cs @@ -53,6 +53,7 @@ public GatewayTestService() typedRequestHandler.Add(typeof(CompleteJobRequest), request => new CompleteJobResponse()); typedRequestHandler.Add(typeof(FailJobRequest), request => new FailJobResponse()); typedRequestHandler.Add(typeof(UpdateJobRetriesRequest), request => new UpdateJobRetriesResponse()); + typedRequestHandler.Add(typeof(UpdateJobTimeoutRequest), request => new UpdateJobTimeoutResponse()); typedRequestHandler.Add(typeof(ThrowErrorRequest), request => new ThrowErrorResponse()); typedRequestHandler.Add(typeof(DeployResourceRequest), request => new DeployResourceResponse()); @@ -106,6 +107,11 @@ public override Task UpdateJobRetries(UpdateJobRetries return Task.FromResult((UpdateJobRetriesResponse)HandleRequest(request, context)); } + public override Task UpdateJobTimeout(UpdateJobTimeoutRequest request, ServerCallContext context) + { + return Task.FromResult((UpdateJobTimeoutResponse)HandleRequest(request, context)); + } + public override Task ThrowError(ThrowErrorRequest request, ServerCallContext context) { return Task.FromResult((ThrowErrorResponse)HandleRequest(request, context)); diff --git a/Client.UnitTests/TestDataProvider.cs b/Client.UnitTests/TestDataProvider.cs index 808587cd..04beabc6 100644 --- a/Client.UnitTests/TestDataProvider.cs +++ b/Client.UnitTests/TestDataProvider.cs @@ -143,6 +143,15 @@ public static IEnumerable Provider() new EvaluateDecisionResponse(), (RequestCreator) (zeebeClient => zeebeClient.NewEvaluateDecisionCommand().DecisionId("decision"))); + yield return new TestCaseData( + new UpdateJobTimeoutRequest() + { + JobKey = 12113L, + Timeout = 20000 + }, new UpdateJobTimeoutResponse(), + (RequestCreator) + (zeebeClient => zeebeClient.NewUpdateJobTimeoutCommand(12113L) + .Timeout(new TimeSpan(0, 0, 0, 20)))); } } } \ No newline at end of file diff --git a/Client.UnitTests/UpdateJobTimeoutTest.cs b/Client.UnitTests/UpdateJobTimeoutTest.cs new file mode 100644 index 00000000..7668c922 --- /dev/null +++ b/Client.UnitTests/UpdateJobTimeoutTest.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using GatewayProtocol; +using Grpc.Core; +using NUnit.Framework; + +namespace Zeebe.Client; + +[TestFixture] +public class UpdateJobTimeoutTest : BaseZeebeTest +{ + [Test] + public async Task ShouldSendRequestAsExpected() + { + // given + var expectedRequest = new UpdateJobTimeoutRequest() + { + JobKey = 1024, + Timeout = 2000 + }; + + // when + await ZeebeClient + .NewUpdateJobTimeoutCommand(1024) + .Timeout(new TimeSpan(0, 0, 2)) + .Send(); + + // then + var request = TestService.Requests[typeof(UpdateJobTimeoutRequest)][0]; + Assert.AreEqual(expectedRequest, request); + } + + [Test] + public void ShouldTimeoutRequest() + { + // given + + // when + var task = ZeebeClient + .NewUpdateJobTimeoutCommand(1024) + .Timeout(new TimeSpan(0, 0, 2)) + .Send(TimeSpan.Zero); + var aggregateException = Assert.Throws(() => task.Wait()); + var rpcException = (RpcException)aggregateException.InnerExceptions[0]; + + // then + Assert.AreEqual(StatusCode.DeadlineExceeded, rpcException.Status.StatusCode); + } + + [Test] + public void ShouldCancelRequest() + { + // given + + // when + var task = ZeebeClient + .NewUpdateJobTimeoutCommand(1024) + .Timeout(new TimeSpan(0, 0, 2)) + .Send(new CancellationTokenSource(TimeSpan.Zero).Token); + var aggregateException = Assert.Throws(() => task.Wait()); + var rpcException = (RpcException)aggregateException.InnerExceptions[0]; + + // then + Assert.AreEqual(StatusCode.Cancelled, rpcException.Status.StatusCode); + } +} \ No newline at end of file diff --git a/Client/Api/Commands/IUpdateJobTimeoutCommandSteps.cs b/Client/Api/Commands/IUpdateJobTimeoutCommandSteps.cs new file mode 100644 index 00000000..210e2d1c --- /dev/null +++ b/Client/Api/Commands/IUpdateJobTimeoutCommandSteps.cs @@ -0,0 +1,25 @@ +using System; +using Zeebe.Client.Api.Responses; + +namespace Zeebe.Client.Api.Commands; + +public interface IUpdateJobTimeoutCommandStep1 +{ + /// + /// Update the timeout for this job. + /// + /// + /// + /// If the job's timeout is set to zero, the job will be directly retried. + /// + /// The duration of the new timeout as a TimeSpan, starting from the current moment. + /// + /// The builder for this command. Call to complete the command and send it to the broker. + /// + IUpdateJobTimeoutCommandStep2 Timeout(TimeSpan timeout); +} + +public interface IUpdateJobTimeoutCommandStep2 : IFinalCommandWithRetryStep +{ + // the place for new optional parameters +} \ No newline at end of file diff --git a/Client/Api/Responses/IUpdateJobTimeoutResponse.cs b/Client/Api/Responses/IUpdateJobTimeoutResponse.cs new file mode 100644 index 00000000..6a0156a2 --- /dev/null +++ b/Client/Api/Responses/IUpdateJobTimeoutResponse.cs @@ -0,0 +1,9 @@ +namespace Zeebe.Client.Api.Responses +{ + /// + /// Response for an update job timeout request. + /// + public interface IUpdateJobTimeoutResponse + { + } +} \ No newline at end of file diff --git a/Client/IZeebeClient.cs b/Client/IZeebeClient.cs index 63abdce7..fd187ae3 100644 --- a/Client/IZeebeClient.cs +++ b/Client/IZeebeClient.cs @@ -118,6 +118,31 @@ public interface IZeebeClient : IJobClient, IDisposable /// IUpdateRetriesCommandStep1 NewUpdateRetriesCommand(long jobKey); + /// + /// Command to update the timeout of a job. + /// + /// + /// + /// long jobKey = ..; + /// + /// zeebeClient + /// .NewUpdateJobTimeoutCommand(jobKey) + /// .Timeout(new TimeSpan(0, 0, 0, 10)) + /// .Send(); + /// + /// + /// + /// + /// If the job's timeout is zero, the job will be directly retried. + /// + /// + /// the key of the job to update + /// + /// + /// a builder for the command + /// + IUpdateJobTimeoutCommandStep1 NewUpdateJobTimeoutCommand(long jobKey); + /// /// Command to deploy new resources, i.e. BPMN process models and DMN decision models. /// diff --git a/Client/Impl/Commands/UpdateJobTimeoutCommand.cs b/Client/Impl/Commands/UpdateJobTimeoutCommand.cs new file mode 100644 index 00000000..458350ac --- /dev/null +++ b/Client/Impl/Commands/UpdateJobTimeoutCommand.cs @@ -0,0 +1,50 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using GatewayProtocol; +using Zeebe.Client.Api.Commands; +using Zeebe.Client.Api.Misc; +using Zeebe.Client.Api.Responses; +using UpdateJobTimeoutResponse = Zeebe.Client.Impl.Responses.UpdateJobTimeoutResponse; + +namespace Zeebe.Client.Impl.Commands; + +public class UpdateJobTimeoutCommand : IUpdateJobTimeoutCommandStep1, IUpdateJobTimeoutCommandStep2 +{ + private readonly UpdateJobTimeoutRequest request; + private readonly Gateway.GatewayClient client; + private readonly IAsyncRetryStrategy asyncRetryStrategy; + + public UpdateJobTimeoutCommand(Gateway.GatewayClient client, IAsyncRetryStrategy asyncRetryStrategy, long jobKey) + { + request = new UpdateJobTimeoutRequest() + { + JobKey = jobKey + }; + this.client = client; + this.asyncRetryStrategy = asyncRetryStrategy; + } + + public IUpdateJobTimeoutCommandStep2 Timeout(TimeSpan timeout) + { + request.Timeout = (long)timeout.TotalMilliseconds; + return this; + } + + public async Task Send(TimeSpan? timeout = null, CancellationToken token = default) + { + var asyncReply = client.UpdateJobTimeoutAsync(request, deadline: timeout?.FromUtcNow(), cancellationToken: token); + await asyncReply.ResponseAsync; + return new UpdateJobTimeoutResponse(); + } + + public async Task Send(CancellationToken cancellationToken) + { + return await Send(token: cancellationToken); + } + + public async Task SendWithRetry(TimeSpan? timeout = null, CancellationToken token = default) + { + return await asyncRetryStrategy.DoWithRetry(() => Send(timeout, token)); + } +} \ No newline at end of file diff --git a/Client/Impl/Responses/UpdateJobTimeoutResponse.cs b/Client/Impl/Responses/UpdateJobTimeoutResponse.cs new file mode 100644 index 00000000..b756edf5 --- /dev/null +++ b/Client/Impl/Responses/UpdateJobTimeoutResponse.cs @@ -0,0 +1,8 @@ +using Zeebe.Client.Api.Responses; + +namespace Zeebe.Client.Impl.Responses; + +public class UpdateJobTimeoutResponse : IUpdateJobTimeoutResponse +{ + +} \ No newline at end of file diff --git a/Client/ZeebeClient.cs b/Client/ZeebeClient.cs index d94e9915..dba709f7 100644 --- a/Client/ZeebeClient.cs +++ b/Client/ZeebeClient.cs @@ -188,6 +188,11 @@ public IUpdateRetriesCommandStep1 NewUpdateRetriesCommand(long jobKey) return new UpdateRetriesCommand(gatewayClient, asyncRetryStrategy, jobKey); } + public IUpdateJobTimeoutCommandStep1 NewUpdateJobTimeoutCommand(long jobKey) + { + return new UpdateJobTimeoutCommand(gatewayClient, asyncRetryStrategy, jobKey); + } + public IThrowErrorCommandStep1 NewThrowErrorCommand(long jobKey) { return new ThrowErrorCommand(gatewayClient, asyncRetryStrategy, jobKey);