Ejemplo n.º 1
0
        public void Nested_command_contexts_maintain_independent_token_sequences()
        {
            var sourceToken  = Guid.NewGuid().ToString();
            var outerCommand = new CommandDelivery <string>("");

            var sequenceWithoutInnerContext = new List <string>();
            var sequenceWithInnerContext    = new List <string>();

            using (var context = DeliveryContext.Establish(outerCommand))
            {
                sequenceWithoutInnerContext.Add(context.NextToken(sourceToken));
                sequenceWithoutInnerContext.Add(context.NextToken(sourceToken));
            }

            using (var outerContext = DeliveryContext.Establish(outerCommand))
            {
                sequenceWithInnerContext.Add(outerContext.NextToken(sourceToken));

                using (var innerCtx = DeliveryContext.Establish(
                           new CommandDelivery <object>(
                               new object(), idempotencyToken: Guid.NewGuid().ToString())))
                {
                    innerCtx.NextToken(Guid.NewGuid().ToString());
                }

                sequenceWithInnerContext.Add(outerContext.NextToken(sourceToken));
            }

            sequenceWithInnerContext.Should().Equal(sequenceWithoutInnerContext);
        }
Ejemplo n.º 2
0
        public void Command_objects_can_specify_idempotency_token_by_implementing_IIdempotent()
        {
            var command = new CreateCommandTarget(Guid.NewGuid().ToString());

            var delivery1 = new CommandDelivery <CreateCommandTarget>(command);
            var delivery2 = new CommandDelivery <CreateCommandTarget>(command);

            delivery1.IdempotencyToken.Should().Be(delivery2.IdempotencyToken);
        }
Ejemplo n.º 3
0
        public void When_a_retry_is_specified_then_the_original_due_time_is_unchanged()
        {
            var originalDueTime = DateTimeOffset.Parse("2018-01-01 12:00pm +00:00", CultureInfo.InvariantCulture);

            var delivery = new CommandDelivery <string>("hello", dueTime: originalDueTime);

            delivery.Retry(1.Days());

            delivery
            .OriginalDueTime
            .Should()
            .Be(originalDueTime);
        }
Ejemplo n.º 4
0
        public void When_a_ret_is_specified_and_the_due_time_was_null_then_the_new_due_time_is_calculated_from_the_current_clock_time()
        {
            using (var clock = VirtualClock.Start())
            {
                var delivery = new CommandDelivery <string>(
                    "hello",
                    dueTime: null);

                delivery.Retry(1.Days());

                delivery
                .DueTime
                .Should()
                .Be(clock.Now() + 1.Days());
            }
        }
Ejemplo n.º 5
0
        public async Task CommandReceiver_Trace_publishes_delivery_properties_as_telemetry_properties()
        {
            // arrange
            var dueTime = DateTimeOffset.Parse("2086-12-05", CultureInfo.InvariantCulture);

            var command = new CreateCommandTarget("the-id");

            var handler = CommandHandler.Create <CreateCommandTarget>(d => d.Complete());

            var delivery = new CommandDelivery <CreateCommandTarget>(
                command,
                idempotencyToken: "the-idempotency-token",
                dueTime: dueTime,
                numberOfPreviousAttempts: 4);
            await configuration.CommandScheduler <CreateCommandTarget>().Schedule(delivery);

            // act
            await configuration.CommandReceiver <CreateCommandTarget>().Receive(handler);

            // assert
            var logEvent = log[4];

            logEvent
            .Category
            .Should()
            .Be("CommandReceiver<CreateCommandTarget>",
                "we're verifying that we have the right log event");

            var properties = logEvent
                             .Evaluate()
                             .Properties;

            properties
            .Should()
            .Contain(t => t.Name == "IdempotencyToken" &&
                     t.Value.As <string>() == "the-idempotency-token");
            properties
            .Should()
            .Contain(t => t.Name == "DueTime" &&
                     t.Value.As <DateTimeOffset>() == dueTime);

            properties
            .Should()
            .Contain(t => t.Name == "NumberOfPreviousAttempts" &&
                     t.Value.As <int>() == 4);
        }
Ejemplo n.º 6
0
        public void Idempotency_tokens_are_generated_by_default_based_on_the_delivery_context_idempotency_token()
        {
            var delivery = new CommandDelivery <string>("hi",
                                                        idempotencyToken: "the-original-idempotency-token");

            string token1, token2;

            using (DeliveryContext.Establish(delivery))
            {
                token1 = new CommandDelivery <string>("").IdempotencyToken;
            }

            using (DeliveryContext.Establish(delivery))
            {
                token2 = new CommandDelivery <string>("").IdempotencyToken;
            }

            token2.Should().Be(token1);
        }
Ejemplo n.º 7
0
        public static CommandDelivery <T> ToCommandDelivery <T>(this Message message)
        {
            var commandJson = Encoding.UTF8.GetString(message.Body);

            var command = commandJson.FromJsonTo <T>();

            var enqueuedTimeUtc = message.SystemProperties.EnqueuedTimeUtc;

            var delivery = new CommandDelivery <T>(
                command,
                dueTime: enqueuedTimeUtc,
                originalDueTime: enqueuedTimeUtc,
                idempotencyToken: message.MessageId,
                numberOfPreviousAttempts: message.SystemProperties.DeliveryCount - 1);

            delivery.Properties["Message"] = message;

            return(delivery);
        }
Ejemplo n.º 8
0
        public void The_default_retry_backoff_is_exponential()
        {
            var retries = Enumerable.Range(0, 5)
                          .Select(i =>
            {
                var delivery = new CommandDelivery <string>("hi", numberOfPreviousAttempts: i);

                return(delivery.Retry());
            });

            retries
            .Select(a => a.RetryPeriod)
            .ShouldBeEquivalentTo(new[]
            {
                1.Minutes(),
                4.Minutes(),
                9.Minutes(),
                16.Minutes(),
                25.Minutes()
            });
        }
Ejemplo n.º 9
0
        public void Different_source_tokens_produce_different_next_tokens()
        {
            var token1    = Guid.NewGuid().ToString();
            var token2    = Guid.NewGuid().ToString();
            var sequence1 = new List <string>();
            var sequence2 = new List <string>();

            var command = new CommandDelivery <string>("");

            using (var ctx = DeliveryContext.Establish(command))
            {
                Enumerable.Range(1, 10).ToList().ForEach(_ => sequence1.Add(ctx.NextToken(token1)));
            }

            using (var ctx = DeliveryContext.Establish(command))
            {
                Enumerable.Range(1, 10).ToList().ForEach(_ => sequence2.Add(ctx.NextToken(token2)));
            }

            sequence1.Should().NotIntersectWith(sequence2);
        }
Ejemplo n.º 10
0
        public void CommandDelivery_Command_can_be_round_tripped_through_service_bus_message()
        {
            var original = new CommandDelivery <MyMessageClass>(
                new MyMessageClass(
                    stringProperty: "oh hello",
                    dateProperty: Clock.Now().Add(2.Days()),
                    nullableDateProperty: Clock.Now().Add(3.Hours()),
                    boolProperty: true,
                    nullableBoolProperty: true,
                    intProperty: 123,
                    nullableIntProperty: 456),
                dueTime: Clock.Now().AddDays(1));

            var message = original.ToMessage();

            SimulateMessageHavingBeenReceived(message);

            var deserialized = message.ToCommandDelivery <MyMessageClass>();

            deserialized.Command.ShouldBeEquivalentTo(original.Command);
        }
Ejemplo n.º 11
0
        public async Task CommandScheduler_Trace_publishes_delivery_properties_as_telemetry_properties()
        {
            // arrange
            var scheduler = CommandScheduler.Create <CreateCommandTarget>(c =>
            {
            }).Trace();

            var delivery = new CommandDelivery <CreateCommandTarget>(
                new CreateCommandTarget("the-id"),
                idempotencyToken: "the-idempotency-token",
                dueTime: DateTimeOffset.Parse("2086-12-05", CultureInfo.InvariantCulture));

            // act
            await scheduler.Schedule(delivery);

            // assert
            var logEvent = log[0];

            logEvent
            .Category
            .Should()
            .Be("CommandScheduler<CreateCommandTarget>",
                "we're verifying that we have the right log event");

            var properties = logEvent
                             .Evaluate()
                             .Properties;

            properties
            .Should()
            .Contain(t => t.Name == "IdempotencyToken" &&
                     t.Value.As <string>() == "the-idempotency-token");
            properties
            .Should()
            .Contain(t => t.Name == "DueTime" &&
                     t.Value.As <DateTimeOffset>() == delivery.DueTime);
        }
Ejemplo n.º 12
0
        public void CommandDelivery_properties_are_initialized_properly_from_a_received_Message()
        {
            using (VirtualClock.Start())
            {
                var message = new CommandDelivery <string>(
                    "hi",
                    dueTime: Clock.Now()).ToMessage();

                SimulateMessageHavingBeenReceived(
                    message,
                    enqueuedTimeUtc: Clock.Now().UtcDateTime);

                var deserialized = message.ToCommandDelivery <string>();

                deserialized
                .DueTime
                .Value
                .UtcDateTime
                .ShouldBeEquivalentTo(
                    message.SystemProperties
                    .EnqueuedTimeUtc);
                deserialized
                .OriginalDueTime
                .Should()
                .Be(
                    message.SystemProperties
                    .EnqueuedTimeUtc);
                deserialized
                .NumberOfPreviousAttempts
                .Should()
                .Be(
                    message
                    .SystemProperties
                    .DeliveryCount - 1);
            }
        }
Ejemplo n.º 13
0
        private void SendCommandInternal <TCommand, TRequest, TResponse>(IComponentWriter writer, bool requireAuthority,
                                                                         ICommandDescriptor <TCommand, TRequest, TResponse> commandDescriptor, TRequest request,
                                                                         EntityId entityId, CommandCallback <TResponse> callback, TimeSpan?timeout, CommandDelivery commandDelivery)
            where TCommand : ICommandMetaclass, new()
        {
            Action sendAction = () =>
            {
                var rawRequest = commandDescriptor.CreateRequest(request);
                Func <ICommandResponse <TCommand>, TResponse> extractResponse =
                    rawResponse => ExtractResponse(commandDescriptor, rawResponse);
                var requestId = componentCommander.SendCommandInternal(entityId, rawRequest, extractResponse, callback, timeout, commandDelivery);
                TrackRequest(writer, requestId);
            };

            SendGenericCommand(writer, requireAuthority, callback, sendAction);
        }
 /// <summary>
 ///     This method is required to prevent Unity compiler issues.
 /// </summary>
 private uint SendCommandRequest <TCommand>(EntityId entityId, ICommandRequest <TCommand> rawRequest, uint timeoutMs, CommandDelivery commandDelivery)
     where TCommand : ICommandMetaclass, new()
 {
     return(communicator.SendCommandRequest(entityId, rawRequest, timeoutMs, commandDelivery).Id);
 }
        public Option <uint> SendCommandInternal <TCommand, TResponse>(EntityId entityId, ICommandRequest <TCommand> rawRequest,
                                                                       Func <ICommandResponse <TCommand>, TResponse> extractResponseFunc, CommandCallback <TResponse> callback,
                                                                       TimeSpan?timeout, CommandDelivery commandDelivery) where TCommand : ICommandMetaclass, new()
        {
            if (!commandResponseThunksRegistered.Contains(typeof(TCommand)))
            {
                var callbackKey = RegisterCommandResponse(extractResponseFunc);
                dispatcherCallbackKeys.Add(callbackKey);
                commandResponseThunksRegistered.Add(typeof(TCommand));
            }

            Func <uint, uint> sendRequestWithTimeoutMs =
                timeoutMs => SendCommandRequest(entityId, rawRequest, timeoutMs, commandDelivery);

            return(SendGenericCommand(callback, sendRequestWithTimeoutMs, timeout));
        }
Ejemplo n.º 16
0
 public void SendCommand <TCommand, TRequest, TResponse>(
     ICommandDescriptor <TCommand, TRequest, TResponse> commandDescriptor, TRequest request,
     EntityId entityId, CommandCallback <TResponse> callback, TimeSpan?timeout = null, CommandDelivery commandDelivery = CommandDelivery.RoundTrip)
     where TCommand : ICommandMetaclass, new()
 {
     SendCommandInternal(null, SkipAuthorityCheck, commandDescriptor, request, entityId, callback, timeout, commandDelivery);
 }
Ejemplo n.º 17
0
 /// <inheritdoc />
 public ICommandResponseHandler <TResponse> SendCommand <TCommand, TRequest, TResponse>(IComponentWriter writer, ICommandDescriptor <TCommand, TRequest, TResponse> commandDescriptor,
                                                                                        TRequest request, EntityId entityId, TimeSpan?timeout, CommandDelivery commandDelivery = CommandDelivery.RoundTrip) where TCommand : ICommandMetaclass, new()
 {
     return(CommandResponseHandler <TResponse> .Wrap(callback => SendCommandInternal(writer, PerformAuthorityCheck, commandDescriptor, request, entityId, callback, timeout, commandDelivery)));
 }
Ejemplo n.º 18
0
        public void Deliveries_have_a_default_idempotency_token()
        {
            var delivery = new CommandDelivery <string>("hi");

            delivery.IdempotencyToken.Should().NotBeNullOrWhiteSpace();
        }
 /// <inheritdoc />
 public void SendCommand <TCommand, TResponse>(EntityId entityId, ICommandRequest <TCommand> rawRequest, Func <ICommandResponse <TCommand>, TResponse> extractResponseFunc,
                                               CommandCallback <TResponse> callback, TimeSpan?timeout = null, CommandDelivery commandDelivery = CommandDelivery.RoundTrip) where TCommand : ICommandMetaclass, new()
 {
     SendCommandInternal(entityId, rawRequest, extractResponseFunc, callback, timeout, commandDelivery);
 }
Ejemplo n.º 20
0
 /// <inheritdoc />
 public RequestId <OutgoingCommandRequest <TCommand> > SendCommandRequest <TCommand>(EntityId entityId, ICommandRequest <TCommand> request, Option <uint> timeout, CommandDelivery commandDelivery) where TCommand : ICommandMetaclass, new()
 {
     return(connection.SendCommandRequest(entityId, request, timeout, new CommandParameters {
         AllowShortCircuiting = commandDelivery == CommandDelivery.ShortCircuit
     }));
 }