/// <inheritdoc /> public async Task <BoolResult> DeleteFingerprintAsync(Context context, StrongFingerprint strongFingerprint) { Stopwatch stopwatch = Stopwatch.StartNew(); try { _cacheTracer.InvalidateCacheEntryStart(context, strongFingerprint); var batch = _dbAdapter.CreateBatchOperation(RedisOperation.DeleteFingerprint); // Tasks var deleteStrongFingerprint = batch.KeyDeleteAsync(_redisSerializer.ToRedisKey(strongFingerprint)).FireAndForgetAndReturnTask(context); var deleteWeakFingerprint = batch.KeyDeleteAsync(_redisSerializer.ToRedisKey(strongFingerprint.WeakFingerprint)).FireAndForgetAndReturnTask(context); await _dbAdapter.ExecuteBatchOperationAsync(context, batch, CancellationToken.None).IgnoreFailure(); await Task.WhenAll(deleteStrongFingerprint, deleteWeakFingerprint); return(BoolResult.Success); } catch (Exception ex) { return(new BoolResult(ex)); } finally { _cacheTracer.InvalidateCacheEntryStop(context, stopwatch.Elapsed); } }
/// <inheritdoc /> public async Task <BoolResult> DeleteFingerprintAsync(Context context, StrongFingerprint strongFingerprint) { Stopwatch stopwatch = Stopwatch.StartNew(); try { _cacheTracer.InvalidateCacheEntryStart(context, strongFingerprint); var batch = _dbAdapter.CreateBatchOperation(RedisOperation.DeleteFingerprint); // Tasks var deleteStrongFingerprint = batch.KeyDeleteAsync(_redisSerializer.ToRedisKey(strongFingerprint)).FireAndForgetAndReturnTask(context); var deleteWeakFingerprint = batch.KeyDeleteAsync(_redisSerializer.ToRedisKey(strongFingerprint.WeakFingerprint)).FireAndForgetAndReturnTask(context); await _dbAdapter.ExecuteBatchOperationAsync(context, batch, CancellationToken.None).IgnoreFailure(); var strongDeleted = await deleteStrongFingerprint; var weakDeleted = await deleteWeakFingerprint; if (!strongDeleted || !weakDeleted) { _tracer.Warning(context, $"Unable to delete some keys. Strong deleted: {strongDeleted}. Weak deleted: {weakDeleted}."); } return(BoolResult.Success); } catch (Exception ex) { return(new BoolResult(ex)); } finally { _cacheTracer.InvalidateCacheEntryStop(context, stopwatch.Elapsed); } }
public async Task ExecuteBatchOperationNoRetryOnRandomExceptions() { // Setup test DB configured to fail 2nd query with normal Exception var testDb = new FailureInjectingRedisDatabase(SystemClock.Instance, InitialTestData) { FailingQuery = 2, ThrowRedisException = false, }; // Setup Redis DB adapter var testConn = MockRedisDatabaseFactory.CreateConnection(testDb); var dbAdapter = new RedisDatabaseAdapter(await RedisDatabaseFactory.CreateAsync(new EnvironmentConnectionStringProvider("TestConnectionString"), testConn), DefaultKeySpace); // Create a batch query var redisBatch = dbAdapter.CreateBatchOperation(RedisOperation.All); var first = redisBatch.StringGetAsync("first"); var second = redisBatch.StringGetAsync("second"); // Execute the batch await dbAdapter.ExecuteBatchOperationAsync(new Context(TestGlobal.Logger), redisBatch, default(CancellationToken)).IgnoreFailure(); // Adapter does not retry in case random exception is thrown Assert.True(testDb.BatchCalled); Assert.Equal(2, testDb.Calls); Assert.NotNull(first.Exception); Assert.NotNull(second.Exception); }
public async Task ExecuteBatchOperationRetriesOnRedisExceptions() { // Setup test DB configured to fail 2nd query with Redis Exception var testDb = new FailureInjectingRedisDatabase(SystemClock.Instance, InitialTestData) { FailingQuery = 2 }; // Setup Redis DB adapter var testConn = MockRedisDatabaseFactory.CreateConnection(testDb); var dbAdapter = new RedisDatabaseAdapter(await RedisDatabaseFactory.CreateAsync(new EnvironmentConnectionStringProvider("TestConnectionString"), testConn), DefaultKeySpace); // Create a batch query var redisBatch = dbAdapter.CreateBatchOperation(RedisOperation.All); var first = redisBatch.StringGetAsync("first"); var second = redisBatch.StringGetAsync("second"); // Execute the batch await dbAdapter.ExecuteBatchOperationAsync(new Context(TestGlobal.Logger), redisBatch, default(CancellationToken)).ShouldBeSuccess(); // Adapter is expected to retry the entire batch if single call fails Assert.True(testDb.BatchCalled); Assert.Equal(4, testDb.Calls); Assert.Null(first.Exception); Assert.Null(second.Exception); Assert.Equal("one", await first); Assert.Equal("two", await second); }
private static Task <BoolResult> ExecuteAsync(RedisDatabaseAdapter adapter, CancellationToken token) { var redisBatch = adapter.CreateBatchOperation(RedisOperation.All); var first = redisBatch.StringGetAsync("first"); // Execute the batch return(adapter.ExecuteBatchOperationAsync(new Context(TestGlobal.Logger), redisBatch, token)); }
public async Task TheClientReconnectsWhenTheNumberOfConnectionIssuesExceedsTheLimit() { // This test checks that if the client fails to connect to redis, it'll successfully reconnect to it. // Setup test DB configured to fail 2nd query with normal Exception var testDb = new FailureInjectingRedisDatabase(SystemClock.Instance, InitialTestData) { // No queries will fail, instead GetDatabase will throw with RedisConnectionException. FailingQuery = -1, }; int numberOfFactoryCalls = 0; // Setup Redis DB adapter Func <IConnectionMultiplexer> connectionMultiplexerFactory = () => { numberOfFactoryCalls++; // Failing connection error only from the first instance. return(MockRedisDatabaseFactory.CreateConnection(testDb, testBatch: null, throwConnectionExceptionOnGet: numberOfFactoryCalls == 1)); }; var redisDatabaseFactory = await RedisDatabaseFactory.CreateAsync(connectionMultiplexerFactory, connectionMultiplexer => BoolResult.SuccessTask); var dbAdapter = new RedisDatabaseAdapter( redisDatabaseFactory, DefaultKeySpace, // If the operation fails we'll retry once and after that we should reset the connection multiplexer so the next operation should create a new one. redisConnectionErrorLimit: 2, retryCount: 1); // Create a batch query var redisBatch = dbAdapter.CreateBatchOperation(RedisOperation.All); // Execute the batch var result = await dbAdapter.ExecuteBatchOperationAsync(new Context(TestGlobal.Logger), redisBatch, default(CancellationToken)); // The first execute batch should fail with the connectivity issue. result.ShouldBeError(); numberOfFactoryCalls.Should().Be(1); var redisBatch2 = dbAdapter.CreateBatchOperation(RedisOperation.All); // Then we should recreate the connection and the second one should be successful. await dbAdapter.ExecuteBatchOperationAsync(new Context(TestGlobal.Logger), redisBatch2, default(CancellationToken)).ShouldBeSuccess(); numberOfFactoryCalls.Should().Be(2); }
private static async Task <Result <bool> > ExecuteAsync(OperationContext context, RedisDatabaseAdapter adapter, CancellationToken token) { var redisBatch = adapter.CreateBatchOperation(RedisOperation.All); var first = redisBatch.StringGetAsync("first"); first.FireAndForget(context, redisBatch); // Execute the batch var result = await adapter.ExecuteBatchOperationAsync(new Context(TestGlobal.Logger), redisBatch, token); if (!result) { return(new ErrorResult(result).AsResult <Result <bool> >()); } return(true); }
private static async Task IncrementWithExpiryValidate( Context context, RedisDatabaseAdapter adapter, ITestRedisDatabase database, string key, uint comparisonValue, TimeSpan specifiedExpiry, int requestedIncrement, long expectedReturnValue, long?expectedIncrementedValue, TimeSpan?expectedDifferentExpiry = null) { var batch = adapter.CreateBatchOperation(RedisOperation.All); var redisKey = GetKey(key); var incrementWithExpire = batch.TryStringIncrementBumpExpiryIfBelowOrEqualValueAsync(key, comparisonValue, timeToLive: specifiedExpiry, requestedIncrement: requestedIncrement); await adapter.ExecuteBatchOperationAsync(context, batch, CancellationToken.None).IgnoreFailure(); var incrementedValue = await incrementWithExpire; Assert.Equal(expectedReturnValue, incrementedValue.AppliedIncrement); var keysWithExpiry = database.GetDbWithExpiry(); if (expectedIncrementedValue == null) { Assert.False(keysWithExpiry.ContainsKey(redisKey)); Assert.Equal(expectedReturnValue, incrementedValue.IncrementedValue); return; } Assert.True(keysWithExpiry.ContainsKey(redisKey)); var expiry = keysWithExpiry[redisKey]; if (expectedDifferentExpiry != null) { Assert.False(expiry.Equals(new MockRedisValueWithExpiry(expectedIncrementedValue, DateTime.UtcNow + specifiedExpiry))); Assert.True(expiry.Equals(new MockRedisValueWithExpiry(expectedIncrementedValue, DateTime.UtcNow + expectedDifferentExpiry.Value))); } else { Assert.True(expiry.Equals(new MockRedisValueWithExpiry(expectedIncrementedValue, DateTime.UtcNow + specifiedExpiry))); } }
private static Task <BoolResult> ExecuteBatchAsync(RedisDatabaseAdapter dbAdapter) => dbAdapter.ExecuteBatchOperationAsync(new Context(TestGlobal.Logger), dbAdapter.CreateBatchOperation(RedisOperation.All), default);