Reputation: 2333
I am pretty new to Redis and am kind of evaluating it. I am using Redis server from here : https://github.com/downloads/dmajkic/redis/redis-2.4.5-win32-win64.zip
I am also using the following config for the server:
port 6379 timeout 300 save 900 1 save 300 10 save 60 10000 loglevel debug logfile stdout databases 1 maxclients 32 maxmemory 2147483648
I am trying to run code like this use ServiceStack client (ServiceStack-ServiceStack.Redis-4add28a)
Here is my code
public void InsertInsideTransaction(bool shouldTransactionRollback)
{
RedisClient transClient = new RedisClient("localhost");
ClearAll();
using (var trans = transClient.CreateTransaction())
{
trans.QueueCommand(r =>
{
var redisUsers = r.GetTypedClient<User>();
var sacha = new User { Id = redisUsers.GetNextSequence(), Name = "Sacha Barber" };
redisUsers.Store(sacha);
//redisUsers.Dispose();
});
//commit or rollback based on incoming flag
if (shouldTransactionRollback)
trans.Rollback();
else
trans.Commit();
IList<User> users = Users();
Console.WriteLine(string.Format("InsertInsideTransaction : There are currently {0}, Users", users.Count()));
}
}
Where User looks like this (from one of the examples that comes with ServiceStack)
public class User
{
public User()
{
this.BlogIds = new List<long>();
}
public long Id { get; set; }
public string Name { get; set; }
public List<long> BlogIds { get; set; }
}
I get this Exception when I try and Commit the Transaction
Unknown reply on multi-request: 43QUEUED, sPort: 60793, LastCommand: EXEC
at ServiceStack.Redis.RedisNativeClient.CreateResponseError(String error) in C:\Users\barbers\Desktop\Downloads\ServiceStack-ServiceStack.Redis-4add28a\ServiceStack-ServiceStack.Redis-4add28a\src\ServiceStack.Redis\RedisNativeClient_Utils.cs:line 146 at ServiceStack.Redis.RedisNativeClient.ReadMultiDataResultCount() in C:\Users\barbers\Desktop\Downloads\ServiceStack-ServiceStack.Redis-4add28a\ServiceStack-ServiceStack.Redis-4add28a\src\ServiceStack.Redis\RedisNativeClient_Utils.cs:line 578 at ServiceStack.Redis.Pipeline.QueuedRedisOperation.ProcessResult() in C:\Users\barbers\Desktop\Downloads\ServiceStack-ServiceStack.Redis-4add28a\ServiceStack-ServiceStack.Redis-4add28a\src\ServiceStack.Redis\Pipeline\QueuedRedisOperation.cs:line 169 at ServiceStack.Redis.RedisTransaction.Commit() in C:\Users\barbers\Desktop\Downloads\ServiceStack-ServiceStack.Redis-4add28a\ServiceStack-ServiceStack.Redis-4add28a\src\ServiceStack.Redis\Transaction\RedisTransaction.cs:line 100 at DocumentDB.Redis.RedisMessAround.InsertInsideTransaction(Boolean shouldTransactionRollback) in C:\Users\barbers\Desktop\DocumentDBs\DocumentDB.Redis\RedisMessAround.cs:line 63 at DocumentDB.Redis.Program.Run() in C:\Users\barbers\Desktop\DocumentDBs\DocumentDB.Redis\Program.cs:line 45 at DocumentDB.Redis.Program.Main(String[] args) in C:\Users\barbers\Desktop\DocumentDBs\DocumentDB.Redis\Program.cs:line 18 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()
I then thought Ok the Redis ServiceStack guys have it working using Transactions in their unit tests, so I edited the "RedisTransactionTests" than came with the ServiceStack client (ServiceStack-ServiceStack.Redis-4add28a) I am using
Here is what I added to the "RedisTransactionTests"
public class User
{
public User()
{
this.BlogIds = new List<long>();
}
public long Id { get; set; }
public string Name { get; set; }
public List<long> BlogIds { get; set; }
}
where I have this edited test code
[Test]
[TestCase(true)]
[TestCase(false)]
public void TestUserTrans(bool shouldTransactionRollback)
{
int count = 0;
IRedisTransaction trans = Redis.CreateTransaction();
try
{
trans.QueueCommand(r =>
{
var redisUsers = r.GetTypedClient<User>();
var sacha = new User { Id = redisUsers.GetNextSequence(), Name = "Sacha Barber" };
redisUsers.Store(sacha);
});
//commit or rollback based on incoming flag
if (shouldTransactionRollback)
trans.Rollback();
else
trans.Commit();
}
catch (Exception ex)
{
}
IList<User> users = Users();
count = users.Count();
Console.WriteLine(string.Format("TestUserTrans : There are currently {0}, Users", users.Count()));
if (shouldTransactionRollback)
Assert.That(count == 0);
else
Assert.That(count == 1);
}
In there the Exception seems to get completely swallowed.
What on earth am I doing wrong
Upvotes: 3
Views: 2738
Reputation: 143399
You can't read and use the results within the same transactions.
Make sure you read on how MULTI/EXEC works: http://redis.io/topics/transactions
It effectively works by batching up multiple commands in a single compound command that is sent and processed by Redis in 1 go.
In your example you're trying to make a read with redisUsers.GetNextSequence()
and use the result from within the queued transaction. You can't do this, instead if you want to make use of variables in your queued transactions you need to read it before:
var sacha = new User {
Id = Redis.As<User>().GetNextSequence(), Name = "Sacha Barber" };
trans.QueueCommand(r => r.As<User>().Store(sacha));
Note: .As<T>()
is a short-hand for r.GetTypedClient<T>()
For transaction integrity on reads you can issue the WATCH command to specify all the variables that your transaction will use. Then if any of those variables are modified before the transaction has completed, an exception will be raised and none of the queued operations will execute.
Upvotes: 5