Exemple #1
0
        public void ReleaseUnheldLock()
        {
            var redisTaskFunnel = CreateRedisTaskFunnel();
            var msgValue        = Guid.NewGuid().ToByteArray();
            var pipeInfo        = PipeInfo.Create("unheld", "a");

            redisTaskFunnel.DestroyChildPipe(pipeInfo);
            var redisPipeValue = new RedisPipeValue(pipeInfo, msgValue, "asdf", true);

            //indicating a success does nothing if the hash doesn't exist
            redisTaskFunnel.AfterExecute(redisPipeValue, true);
            var readMessage = redisTaskFunnel.TryReadMessageBatch(false, pipeInfo, TimeSpan.FromMinutes(1), 1);

            readMessage.RedisValues.Should().BeEmpty();

            //indicating a failure resubmits the message
            redisTaskFunnel.AfterExecute(redisPipeValue, false);
            readMessage = redisTaskFunnel.TryReadMessageBatch(false, pipeInfo, TimeSpan.FromMinutes(1), 1);
            readMessage.Should().NotBeNull();
            var mesg = readMessage.RedisPipeValues.FirstOrDefault();

            mesg?.Value.Should().BeEquivalentTo(msgValue);
            redisTaskFunnel.DestroyChildPipe(pipeInfo);
            redisTaskFunnel.AfterExecuteBatch(readMessage);
        }
        private static void SendReadAndRelease(IRedisTaskFunnel redisTaskFunnel, string parentPipeName, string childPipeName)
        {
            var sent = redisTaskFunnel.TrySendMessage(parentPipeName, childPipeName, new byte[1] {
                (byte)'a'
            }, Int32.MaxValue,
                                                      TimeSpan.FromMinutes(1));

            sent.sent.Should().BeTrue();
            sent.clients.Should().BeFalse();

            var read = redisTaskFunnel.TryReadMessage <byte[]>(true, parentPipeName, childPipeName, TimeSpan.FromSeconds(1));

            read.Should().NotBeNull();
            read.LockValue.Should().NotBeNull();
            read.Value.Should().NotBeNull();

            //try to release the lock without the correct key
            var redisPipeValue = new RedisPipeValue <byte[]>(PipeInfo.Create(parentPipeName, childPipeName), "", Guid.NewGuid().ToString(), true);
            var badExtend      = redisTaskFunnel.LockExtend(redisPipeValue, TimeSpan.FromSeconds(1));

            badExtend.Should().BeFalse();
            Action badRelease = () => redisTaskFunnel.LockRelease(redisPipeValue, true);

            badRelease.Should().Throw <ApplicationException>();

            var extended = redisTaskFunnel.LockExtend(read, TimeSpan.FromSeconds(1));

            extended.Should().BeTrue();

            var released = redisTaskFunnel.LockRelease(read, true);

            released.Should().BeTrue();
        }
        private void ExecuteExisting(TimeSpan lockExpiry)
        {
            var sourcePipes = GetSourcePipes();
            var tasks       = new List <Task>();

            foreach (var sourcePipe in sourcePipes)
            {
                foreach (var sourcePipeChild in sourcePipe.Value)
                {
                    var pipeInfo = PipeInfo.Create(sourcePipe.Key, sourcePipeChild);
                    //capture the number of reads write now to ignore:
                    // - new events that arrive
                    // - events that fail and are re-added.
                    var maxReads     = _taskFunnel.GetListLength(pipeInfo);
                    var batchSize    = 2;
                    var messageBatch = _taskFunnel.TryReadMessageBatch(true, pipeInfo, lockExpiry, batchSize);

                    //this is still an early implementation.  The objectives are:
                    //  - speed (obviously)
                    //  - consistent number of active tasks.
                    //  - batches released as soon as the last one completes

                    while (messageBatch?.HoldingList != null)
                    {
                        var taskExecutor = _taskExecutors[sourcePipe.Key];
                        ExecuteBatch(taskExecutor, pipeInfo, messageBatch);
                        messageBatch = _taskFunnel.TryReadMessageBatch(true, pipeInfo, lockExpiry, batchSize);
                    }
                }
            }
        }
Exemple #4
0
        public void ReadFromNonExistantOrEmptyQueue()
        {
            var redisTaskFunnel = CreateRedisTaskFunnel();
            var read            = redisTaskFunnel.TryReadMessageBatch(true, PipeInfo.Create("emptyqueue", "emptypipe"), TimeSpan.FromSeconds(10), 1);

            read.HoldingList.Should().BeNull();
            read.RedisValues.Should().BeEmpty();
        }
        public void ReleaseLockExtend()
        {
            var redisTaskFunnel = CreateRedisTaskFunnel();
            var lockKey         = Guid.NewGuid().ToString();
            var redisPipeValue  = new RedisPipeValue <byte[]>(PipeInfo.Create("lock", "a"), lockKey, "asdf", true);
            var extended        = redisTaskFunnel.LockExtend(redisPipeValue, TimeSpan.FromMinutes(1));

            extended.Should().BeFalse();
        }
        public void ReleaseUnheldLock()
        {
            var redisTaskFunnel = CreateRedisTaskFunnel();
            var lockKey         = Guid.NewGuid().ToString();
            var redisPipeValue  = new RedisPipeValue <byte[]>(PipeInfo.Create("unheld", "a"), lockKey, "asdf", true);

            Action act = () => redisTaskFunnel.LockRelease(redisPipeValue, true);

            act.Should().Throw <ApplicationException>();
        }
Exemple #7
0
        public void ReleaseLockExtend()
        {
            var redisTaskFunnel = CreateRedisTaskFunnel();
            var lockKey         = Guid.NewGuid().ToString();
            var pipeInfo        = PipeInfo.Create("lock", "a");
            var redisPipeValue  = new RedisPipeValue(pipeInfo, lockKey, "asdf", true);
            var extended        = redisTaskFunnel.RetainHoldingList(redisPipeValue, TimeSpan.FromMinutes(1));

            extended.Should().BeFalse();
            redisTaskFunnel.DestroyChildPipe(pipeInfo);
        }
Exemple #8
0
        public void ListenForPipeEvents(/*IEnumerable<string> parentPipeNames,*/
            BlockingCollection <PipeInfo> pipeInfos)
        {
            var sub = _redis.GetSubscriber();

            //foreach (var parentPipeName in parentPipeNames){}
            sub.Subscribe(RedisTaskMultiplexorConstants.RedisTaskMultiplexorBroadcastPrefix, (channel, value) =>
            {
                var eventObject = JObject.Parse(value);
                //$"{{\"type\":\"new\",\"parent\":\"{parentPipeName}\",\"child\":\"{childPipeName}\"}}");
                var parent        = eventObject["parent"].ToString();
                var child         = eventObject["child"].ToString();
                var eventPipeInfo = PipeInfo.Create(parent, child);
                pipeInfos.Add(eventPipeInfo);
            });
        }
Exemple #9
0
        public void TestSendAndRecover()
        {
            var redisTaskFunnel = CreateRedisTaskFunnel();
            var parentPipeName  = "SendAndRecover";
            var childPipeName   = Guid.NewGuid().ToString();

            //send 2 messages
            var messageBody1 = "body1";
            var sent         = redisTaskFunnel.TrySendMessage(parentPipeName, childPipeName, messageBody1, Int32.MaxValue,
                                                              TimeSpan.FromMinutes(1));

            sent.sent.Should().BeTrue();
            var messageBody2 = "body2";

            sent = redisTaskFunnel.TrySendMessage(parentPipeName, childPipeName, messageBody2, Int32.MaxValue,
                                                  TimeSpan.FromMinutes(1));
            sent.sent.Should().BeTrue();
            //sent.clients.Should().BeFalse();

            //read the batch
            var pipeInfo = PipeInfo.Create(parentPipeName, childPipeName);
            var read     = redisTaskFunnel.TryReadMessageBatch(true, pipeInfo, TimeSpan.FromSeconds(1), 2);

            read.Should().NotBeNull();
            read.HoldingList.Should().NotBeNull();
            read.RedisValues.Count.Should().Be(2);
            read.RedisValues.First().HasValue.Should().BeTrue();
            read.RedisValues.Skip(1).First().HasValue.Should().BeTrue();
            read.RedisPipeValues.Any(a => a.ValueString == messageBody1).Should().BeTrue();
            read.RedisPipeValues.Any(a => a.ValueString == messageBody2).Should().BeTrue();

            //recover batch (redeliver its messages)
            redisTaskFunnel.RecoverBatch(read.HoldingList).Should().BeTrue();
            read = redisTaskFunnel.TryReadMessageBatch(true, pipeInfo, TimeSpan.FromSeconds(1), 2);
            read.Should().NotBeNull();
            read.HoldingList.Should().NotBeNull();
            read.RedisValues.Count.Should().Be(2);
            read.RedisValues.First().HasValue.Should().BeTrue();
            read.RedisValues.Skip(1).First().HasValue.Should().BeTrue();
            var actualRedisPipeValue = read.RedisPipeValues.First();

            read.RedisPipeValues.Any(a => a.ValueString == messageBody1).Should().BeTrue();
            read.RedisPipeValues.Any(a => a.ValueString == messageBody2).Should().BeTrue();
        }
Exemple #10
0
        private static void SendReadAndRelease(IRedisTaskFunnel redisTaskFunnel, string parentPipeName, string childPipeName)
        {
            //send a message
            var messageBody = "body";
            var sent        = redisTaskFunnel.TrySendMessage(parentPipeName, childPipeName, messageBody, Int32.MaxValue,
                                                             TimeSpan.FromMinutes(1));

            sent.sent.Should().BeTrue();
            //sent.clients.Should().BeFalse();

            //read the batch
            var read = redisTaskFunnel.TryReadMessageBatch(true, PipeInfo.Create(parentPipeName, childPipeName), TimeSpan.FromSeconds(1), 1);

            read.Should().NotBeNull();
            read.HoldingList.Should().NotBeNull();
            read.RedisValues.Should().NotBeEmpty();
            read.RedisValues.First().HasValue.Should().BeTrue();
            var actualRedisPipeValue = read.RedisPipeValues.First();

            actualRedisPipeValue.ValueString.Should().Be(messageBody);

            //try to release the lock without the wrong holdingListName
            var redisPipeValue = new RedisPipeValue(PipeInfo.Create(parentPipeName, childPipeName), "body", Guid.NewGuid().ToString(), true);
            var badExtend      = redisTaskFunnel.RetainHoldingList(redisPipeValue, TimeSpan.FromSeconds(1));

            badExtend.Should().BeFalse();
            redisTaskFunnel.AfterExecute(redisPipeValue, true);

            //retain with the correct name
            var extended = redisTaskFunnel.RetainHoldingList(read, TimeSpan.FromSeconds(1));

            extended.Should().BeTrue();

            //complete the message and the batch
            redisTaskFunnel.AfterExecute(actualRedisPipeValue, true);
            redisTaskFunnel.AfterExecuteBatch(read);

            //now check the holding list doesn't exist any more.
            extended = redisTaskFunnel.RetainHoldingList(read, TimeSpan.FromSeconds(1));
            extended.Should().BeFalse();
        }
Exemple #11
0
        public (bool sent, bool clients) TrySendMessage(string parentPipeName, string childPipeName, object body, int maxListLength = int.MaxValue, TimeSpan?expiry = null)
        {
            if (body == null)
            {
                throw new ArgumentNullException(nameof(body));
            }
            //will throw ArgumentException is body is not a supported type
            var redisValue = RedisValue.Unbox(body);

            var db             = _redis.GetDatabase();
            var parentInfoPath = CreateParentChildSetPath(parentPipeName);
            var childPipePath  = PipeInfo.Create(parentPipeName, childPipeName);
            var trans          = db.CreateTransaction();
            {
                if (maxListLength < int.MaxValue)
                {
                    trans.AddCondition(Condition.ListLengthLessThan(childPipePath.PipePath, maxListLength));
                }

                //ensure the name of the new pipe exists for the pipe monitor (before checking list length)
                db.SetAdd(RedisTaskMultiplexorConstants.PipeNameSetKey, parentPipeName);

                //add the child to the parents hash set (and update the expiry time on it)
                db.HashSet(parentInfoPath, childPipeName, DateConverters.ExpiryToTimeString(expiry ?? TimeSpan.FromDays(7)));

                //add the message to the left of the list, and is later popped from the right.
                db.ListLeftPush(childPipePath.PipePath, redisValue);
            }
            var executed = trans.Execute();

            if (!executed)
            {
                return(false, false);
            }

            var sub       = _redis.GetSubscriber();
            var listeners = sub.Publish(childPipePath.BroadcastPath, $"{{\"type\":\"new\",\"parent\":\"{parentPipeName}\",\"child\":\"{childPipeName}\"}}");

            return(true, listeners > 0);
        }