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); }
public void AfterExecute(RedisPipeValue value, bool success) { var db = _redis.GetDatabase(); if (!success) { //this is a Nack //whether we peeked it or not, just push it back where it was db.ListLeftPush(value.PipeInfo.PipePath, value.RedisValue); } else { if (value.Peaked) { //when we peeked it, we moved the record to a 'holding list' //whether the invocation failed or succeeded we don't remove it from that list to minimize load on redis. //This means that if the application crashes before the batch is destroyed the batch will be resubmitted //So that makes the chance that this message will be re-executed twice: once from the re-push above //and once from the batch re-submission //later we can add a release strategy to do this: db.ListRemove(value.BatchHoldingList, value.RedisValue, 1); //or perhaps we can use the NThen redis data that tracks individual messages } else { //when we originally read the message we just removed it from the list, so we definitely dont need to do anything } } }
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(); }
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>(); }
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); }
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(); }
public bool RetainHoldingList(RedisPipeValue value, TimeSpan lockExpiry) { return(RetainHoldingList(value.BatchHoldingList, lockExpiry)); }
public Task ExecuteAsync(PipeInfo pipeInfo, RedisPipeValue value) { Execute(pipeInfo, value); return(Task.CompletedTask); }
public void Execute(PipeInfo pipeInfo, RedisPipeValue value) { var valueAsString = value.ValueString; System.Diagnostics.Debug.WriteLine($"{pipeInfo.ParentPipeName}/{pipeInfo.ChildPipeName} : {valueAsString}"); }