Exemple #1
0
        /// <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);
            }
        }
Exemple #2
0
        /// <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);
            }
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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));
        }
Exemple #6
0
        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);