public void Can_handle_requests_concurrently_in_4_threads(int noOfThreads, int msgs) { var timesCalled = 0; using var mqHost = new ServiceBusMqServer(ConnectionString); var queueNames = QueueNames <Wait> .AllQueueNames.Select(SafeQueueName).ToList(); #if NETCOREAPP2_1 queueNames.ForEach(q => mqHost.ManagementClient.DeleteQueueAsync(q).GetAwaiter().GetResult()); #else queueNames.ForEach(q => mqHost.NamespaceManager.DeleteQueue(q)); #endif mqHost.RegisterHandler <Wait>(m => { Interlocked.Increment(ref timesCalled); Thread.Sleep(m.GetBody().ForMs); return(null); }, noOfThreads); mqHost.Start(); var dto = new Wait { ForMs = 100 }; using var mqClient = mqHost.CreateMessageQueueClient(); msgs.Times(i => mqClient.Publish(dto)); ExecUtils.RetryUntilTrue(() => timesCalled == msgs, TimeSpan.FromSeconds(5)); }
public RedisLock(IRedisClient redisClient, string key, TimeSpan?timeout) { this._redisClient = redisClient; this._key = key; bool LockAction() { // This pattern is taken from the redis command for SETNX http://redis.io/commands/setnx // Calculate a unix time for when the lock should expire var realSpan = timeout ?? new TimeSpan(365, 0, 0, 0); // if nothing is passed in the timeout hold for a year var expireTime = DateTime.UtcNow.Add(realSpan); var lockString = (expireTime.ToUnixTimeMs() + 1).ToString(); // Try to set the lock, if it does not exist this will succeed and the lock is obtained var nx = redisClient.SetValueIfNotExists(key, lockString); if (nx) { return(true); } // If we've gotten here then a key for the lock is present. This could be because the lock is // correctly acquired or it could be because a client that had acquired the lock crashed (or didn't release it properly). // Therefore we need to get the value of the lock to see when it should expire redisClient.Watch(key); var lockExpireString = redisClient.Get <string>(key); if (!long.TryParse(lockExpireString, out var lockExpireTime)) { redisClient.UnWatch(); // since the client is scoped externally return(false); } // If the expire time is greater than the current time then we can't let the lock go yet if (lockExpireTime > DateTime.UtcNow.ToUnixTimeMs()) { redisClient.UnWatch(); // since the client is scoped externally return(false); } // If the expire time is less than the current time then it wasn't released properly and we can attempt to // acquire the lock. The above call to Watch(_lockKey) enrolled the key in monitoring, so if it changes // before we call Commit() below, the Commit will fail and return false, which means that another thread // was able to acquire the lock before we finished processing. using (var trans = redisClient.CreateTransaction()) { // we started the "Watch" above; this tx will succeed if the value has not moved trans.QueueCommand(r => r.Set(key, lockString)); return(trans.Commit()); // returns false if Transaction failed } } ExecUtils.RetryUntilTrue(LockAction, timeout); }
internal long AtomicIncDec(string key, long amount) { long count = 0; bool updated = false; ExecUtils.RetryUntilTrue(() => { var entry = GetEntry(key); if (entry == null) { count = amount; entry = CreateTableEntry(key, Serialize(count)); try { updated = table.Execute(TableOperation.Insert(entry)).HttpStatusCode == (int)HttpStatusCode.NoContent; } catch (StorageException ex) { if (!ex.InnerException.HasStatus(HttpStatusCode.Conflict)) { throw; } } } else { count = Deserialize <long>(entry.Data) + amount; entry.Data = Serialize <long>(count); var op = TableOperation.Replace(entry); try { var result = table.Execute(op).HttpStatusCode; updated = result == (int)HttpStatusCode.OK || result == (int)HttpStatusCode.NoContent; } catch (StorageException ex) { if (!ex.InnerException.HasStatus(HttpStatusCode.PreconditionFailed)) { throw; } } } return(updated); }, TimeSpan.FromSeconds(30)); return(count); }
public void RedisLock(IRedisClient redisClient, string key, TimeSpan?timeOut) { //this.redisClient = redisClient; //this.key = key; ExecUtils.RetryUntilTrue(delegate { TimeSpan value = timeOut ?? new TimeSpan(365, 0, 0, 0); DateTime dateTime = DateTime.UtcNow.Add(value); string lockString = (dateTime.ToUnixTimeMs() + 1).ToString(); if (redisClient.SetValueIfNotExists(key, lockString)) { return(true); } redisClient.Watch(key); long result = -1L; string s = redisClient.Get <string>(key); if (!long.TryParse(s, out result)) { redisClient.UnWatch(); return(false); } if (result <= DateTime.UtcNow.ToUnixTimeMs()) { using (IRedisTransaction redisTransaction = redisClient.CreateTransaction()) { redisTransaction.QueueCommand((IRedisClient r) => r.Set(key, lockString)); System.Threading.Thread.Sleep(5 * 1000); bool ok = redisTransaction.Commit(); var lockString2 = redisClient.Get <string>(key); if (lockString2 != lockString) { } return(ok); } } redisClient.UnWatch(); return(false); }, timeOut); }
public virtual void WaitForWorkersToStop(TimeSpan?timeout = null) { ExecUtils.RetryUntilTrue( () => Interlocked.CompareExchange(ref status, 0, 0) == WorkerStatus.Stopped, timeout); }