private async Task <TestConnectionData> TestConnectionAsync(string connectionString, string name, DatabaseType databaseType = DatabaseType.Dynamic)
        {
            TestConnectionData data = new TestConnectionData();

            data.ConnectionString = connectionString;
            data.Name             = name;
            CloudStorageAccount csa = null;

            try
            {
                if (databaseType == DatabaseType.SqlDatabase || databaseType == DatabaseType.SqlServer)
                {
                    using (SqlConnection conn = new SqlConnection())
                    {
                        conn.ConnectionString = connectionString;
                        await conn.OpenAsync();

                        data.Succeeded = true;
                    }
                }
                else if (databaseType == DatabaseType.MySql)
                {
                    using (MySqlConnection conn = new MySqlConnection())
                    {
                        conn.ConnectionString = connectionString;
                        await conn.OpenAsync();

                        data.Succeeded = true;
                    }
                }
                else if (databaseType == DatabaseType.PostgreSql)
                {
                    using (NpgsqlConnection conn = new NpgsqlConnection())
                    {
                        conn.ConnectionString = connectionString;
                        await conn.OpenAsync();

                        data.Succeeded = true;
                    }
                }
                else if (databaseType == DatabaseType.RedisCache)
                {
                    using (var muxer = await ConnectionMultiplexer.ConnectAsync(connectionString))
                    {
                        data.Succeeded = true;
                    }
                }
                else if (databaseType == DatabaseType.Dynamic)
                {
                    using (SqlConnection conn = new SqlConnection())
                    {
                        conn.ConnectionString = connectionString;
                        await conn.OpenAsync();

                        data.Succeeded = true;
                    }
                }
                else if (databaseType == DatabaseType.NotSupported)
                {
                    throw new Exception("This type of connection string is not yet supported by this tool");
                }

                else if (databaseType == DatabaseType.Custom)
                {
                    if (connectionString.StartsWith("metadata=res://", StringComparison.OrdinalIgnoreCase))
                    {
                        data.IsEntityFramework = true;
                        var ec = new EntityConnectionStringBuilder(connectionString);
                        using (var connection = CreateDbConnection(ec.Provider, ec.ProviderConnectionString))
                        {
                            if (connection != null)
                            {
                                await connection.OpenAsync();

                                data.Succeeded = true;
                            }
                        }
                    }
                    else if (connectionString.IndexOf("Driver=", StringComparison.OrdinalIgnoreCase) >= 0)
                    {
                        data.IsCustomDriver = true;
                        using (OdbcConnection conn = new OdbcConnection())
                        {
                            conn.ConnectionString = connectionString;
                            await conn.OpenAsync();

                            data.Succeeded = true;
                        }
                    }
                    else if (CloudStorageAccount.TryParse(connectionString, out csa))
                    {
                        data.IsAzureStorage = true;
                        var cloudTableClient = csa.CreateCloudTableClient();
                        var tableNames       = await cloudTableClient.ListTablesSegmentedAsync(null);

                        data.Succeeded = true;
                    }
                    else
                    {
                        throw new Exception("Failed to determine the kind of connection string");
                    }
                }
            }
            catch (Exception exception)
            {
                data.ExceptionDetails = exception;
            }
            return(data);
        }
Example #2
0
        public RedisService(IConfiguration configuration)
        {
            var config = $"{configuration["Redis:Host"]}:{configuration["Redis:Port"]}";

            _redis = ConnectionMultiplexer.ConnectAsync(config).GetAwaiter().GetResult();
        }
Example #3
0
        public override async Task SendAsync(EventMessage message)
        {
            AuditRecord record = null;

            byte[]       payload = null;
            EventMessage msg     = null;

            if (connection == null || !connection.IsConnected)
            {
                connection = await ConnectionMultiplexer.ConnectAsync(connectionString);
            }

            await tqueue.Enqueue(() => cqm.EnqueueAsync(message));

            try
            {
                while (!cqm.IsEmpty)
                {
                    msg = await cqm.DequeueAsync();

                    string cacheKey = GetKey(msg);

                    if (cacheKey == null)
                    {
                        Trace.TraceWarning("Redis sink has no cache key for subscription '{0}'.", this.metadata.SubscriptionUriString);
                        Trace.TraceError("No cache key found.");
                    }

                    payload = GetPayload(msg);

                    if (payload.Length == 0)
                    {
                        throw new InvalidOperationException("Payload length is 0.");
                    }


                    if (msg.ContentType != "application/octet-stream")
                    {
                        Task task      = database.StringSetAsync(cacheKey, Encoding.UTF8.GetString(payload), expiry);
                        Task innerTask = task.ContinueWith(async(a) => { await FaultTask(msg, message.Audit); }, TaskContinuationOptions.OnlyOnFaulted);
                        await Task.WhenAll(task);
                    }
                    else
                    {
                        Task task      = database.StringSetAsync(cacheKey, payload, expiry);
                        Task innerTask = task.ContinueWith(async(a) => { await FaultTask(msg, message.Audit); }, TaskContinuationOptions.OnlyOnFaulted);
                        await Task.WhenAll(task);
                    }

                    record = new MessageAuditRecord(msg.MessageId, uri.Query.Length > 0 ? uri.ToString().Replace(uri.Query, "") : uri.ToString(), String.Format("Redis({0})", dbNumber), String.Format("Redis({0})", dbNumber), payload.Length, MessageDirectionType.Out, true, DateTime.UtcNow);
                }
            }
            catch (Exception ex)
            {
                Trace.TraceWarning("Initial Redis write error {0}", ex.Message);
                record = new MessageAuditRecord(msg.MessageId, uri.Query.Length > 0 ? uri.ToString().Replace(uri.Query, "") : uri.ToString(), String.Format("Redis({0})", dbNumber), String.Format("Redis({0})", dbNumber), payload.Length, MessageDirectionType.Out, false, DateTime.UtcNow, ex.Message);
            }
            finally
            {
                if (message.Audit && record != null)
                {
                    await auditor?.WriteAuditRecordAsync(record);
                }
            }
        }
Example #4
0
        protected virtual ConnectionMultiplexer Create(
            string clientName    = null, int?syncTimeout           = null, bool?allowAdmin          = null, int?keepAlive  = null,
            int?connectTimeout   = null, string password           = null, string tieBreaker        = null, TextWriter log = null,
            bool fail            = true, string[] disabledCommands = null, string[] enabledCommands = null,
            bool checkConnect    = true, bool pause                = true, string failMessage = null,
            string channelPrefix = null, bool useSharedSocketManager = true, Proxy?proxy = null)
        {
            if (pause)
            {
                Thread.Sleep(250);        // get a lot of glitches when hammering new socket creations etc; pace it out a bit
            }
            string configuration = GetConfiguration();
            var    config        = ConfigurationOptions.Parse(configuration);

            if (disabledCommands != null && disabledCommands.Length != 0)
            {
                config.CommandMap = CommandMap.Create(new HashSet <string>(disabledCommands), false);
            }
            else if (enabledCommands != null && enabledCommands.Length != 0)
            {
                config.CommandMap = CommandMap.Create(new HashSet <string>(enabledCommands), true);
            }

            if (Debugger.IsAttached)
            {
                syncTimeout = int.MaxValue;
            }

            if (useSharedSocketManager)
            {
                config.SocketManager = socketManager;
            }
            if (channelPrefix != null)
            {
                config.ChannelPrefix = channelPrefix;
            }
            if (tieBreaker != null)
            {
                config.TieBreaker = tieBreaker;
            }
            if (password != null)
            {
                config.Password = string.IsNullOrEmpty(password) ? null : password;
            }
            if (clientName != null)
            {
                config.ClientName = clientName;
            }
            if (syncTimeout != null)
            {
                config.SyncTimeout = syncTimeout.Value;
            }
            if (allowAdmin != null)
            {
                config.AllowAdmin = allowAdmin.Value;
            }
            if (keepAlive != null)
            {
                config.KeepAlive = keepAlive.Value;
            }
            if (connectTimeout != null)
            {
                config.ConnectTimeout = connectTimeout.Value;
            }
            if (proxy != null)
            {
                config.Proxy = proxy.Value;
            }
            var watch = Stopwatch.StartNew();
            var task  = ConnectionMultiplexer.ConnectAsync(config, log ?? Writer);

            if (!task.Wait(config.ConnectTimeout >= (int.MaxValue / 2) ? int.MaxValue : config.ConnectTimeout * 2))
            {
                task.ContinueWith(x =>
                {
                    try
                    {
                        GC.KeepAlive(x.Exception);
                    }
                    catch
                    { }
                }, TaskContinuationOptions.OnlyOnFaulted);
                throw new TimeoutException("Connect timeout");
            }
            watch.Stop();
            if (Output == null)
            {
                Assert.True(false, "Failure: Be sure to call the TestBase constuctor like this: BasicOpsTests(ITestOutputHelper output) : base(output) { }");
            }
            Output.WriteLine("Connect took: " + watch.ElapsedMilliseconds + "ms");
            var muxer = task.Result;

            if (checkConnect && (muxer == null || !muxer.IsConnected))
            {
                // If fail is true, we throw.
                Assert.False(fail, failMessage + "Server is not available");
                Skip.Inconclusive(failMessage + "Server is not available");
            }
            muxer.InternalError    += OnInternalError;
            muxer.ConnectionFailed += OnConnectionFailed;
            return(muxer);
        }
Example #5
0
        public Redis()
        {
            var cstr = ConfigurationManager.ConnectionStrings["TestRedis"].ConnectionString;

            Connection = ConnectionMultiplexer.ConnectAsync(cstr + ",allowAdmin=true").Result;
        }
Example #6
0
        public async Task LoadServicesAsync(MikiAppBuilder app)
        {
            new LogBuilder()
            .AddLogEvent((msg, lvl) =>
            {
                if (lvl >= Global.Config.LogLevel)
                {
                    Console.WriteLine(msg);
                }
            })
            .SetLogHeader((msg) => $"[{msg}]: ")
            .SetTheme(new LogTheme())
            .Apply();

            var cache = new StackExchangeCacheClient(
                new ProtobufSerializer(),
                await ConnectionMultiplexer.ConnectAsync(Global.Config.RedisConnectionString)
                );

            // Setup Redis
            {
                app.AddSingletonService <ICacheClient>(cache);
                app.AddSingletonService <IExtendedCacheClient>(cache);
            }

            // Setup Entity Framework
            {
                app.Services.AddDbContext <MikiDbContext>(x
                                                          => x.UseNpgsql(Global.Config.ConnString, b => b.MigrationsAssembly("Miki.Bot.Models")));
                app.Services.AddDbContext <DbContext, MikiDbContext>(x
                                                                     => x.UseNpgsql(Global.Config.ConnString, b => b.MigrationsAssembly("Miki.Bot.Models")));
            }

            // Setup Miki API
            {
                if (!string.IsNullOrWhiteSpace(Global.Config.MikiApiBaseUrl) && !string.IsNullOrWhiteSpace(Global.Config.MikiApiKey))
                {
                    app.AddSingletonService(new MikiApiClient(Global.Config.MikiApiKey));
                }
                else
                {
                    Log.Warning("No Miki API parameters were supplied, ignoring Miki API.");
                }
            }

            // Setup Discord
            {
                app.AddSingletonService <IApiClient>(new DiscordApiClient(Global.Config.Token, cache));
                if (Global.Config.SelfHosted)
                {
                    var gatewayConfig = new GatewayProperties();
                    gatewayConfig.ShardCount             = 1;
                    gatewayConfig.ShardId                = 0;
                    gatewayConfig.Token                  = Global.Config.Token;
                    gatewayConfig.Compressed             = true;
                    gatewayConfig.AllowNonDispatchEvents = true;
                    app.AddSingletonService <IGateway>(new GatewayCluster(gatewayConfig));
                }
                else
                {
                    app.AddSingletonService <IGateway>(new DistributedGateway(new MessageClientConfiguration
                    {
                        ConnectionString = new Uri(Global.Config.RabbitUrl.ToString()),
                        QueueName        = "gateway",
                        ExchangeName     = "consumer",
                        ConsumerAutoAck  = false,
                        PrefetchCount    = 25,
                    }));
                }
            }

            // Setup web services
            {
                app.AddSingletonService(new UrbanDictionaryAPI());
                app.AddSingletonService(new BunnyCDNClient(Global.Config.BunnyCdnKey));
            }

            // Setup miscellanious services
            {
                app.AddSingletonService(new ConfigurationManager());
                app.AddSingletonService(new EventSystem());
                app.AddSingletonService(new BackgroundStore());

                if (!string.IsNullOrWhiteSpace(Global.Config.SharpRavenKey))
                {
                    app.AddSingletonService(new RavenClient(Global.Config.SharpRavenKey));
                }
                else
                {
                    Log.Warning("Sentry.io key not provided, ignoring distributed error logging...");
                }
            }
        }
        private async Task <IConnectionMultiplexer> ConnectionFactory(string connection, TextWriter writer)
        {
            var conn = await ConnectionMultiplexer.ConnectAsync(connection, writer);

            return(conn);
        }
        public async Task FailFast()
        {
            void PrintSnapshot(ConnectionMultiplexer muxer)
            {
                Writer.WriteLine("Snapshot summary:");
                foreach (var server in muxer.GetServerSnapshot())
                {
                    Writer.WriteLine($"  {server.EndPoint}: ");
                    Writer.WriteLine($"     Type: {server.ServerType}");
                    Writer.WriteLine($"     IsConnected: {server.IsConnected}");
                    Writer.WriteLine($"      IsConnecting: {server.IsConnecting}");
                    Writer.WriteLine($"      IsSelectable(allowDisconnected: true): {server.IsSelectable(RedisCommand.PING, true)}");
                    Writer.WriteLine($"      IsSelectable(allowDisconnected: false): {server.IsSelectable(RedisCommand.PING, false)}");
                    Writer.WriteLine($"      UnselectableFlags: {server.GetUnselectableFlags()}");
                    var bridge = server.GetBridge(RedisCommand.PING, create: false);
                    Writer.WriteLine($"      GetBridge: {bridge}");
                    Writer.WriteLine($"        IsConnected: {bridge.IsConnected}");
                    Writer.WriteLine($"        ConnectionState: {bridge.ConnectionState}");
                }
            }

            try
            {
                // Ensuring the FailFast policy errors immediate with no connection available exceptions
                var options = new ConfigurationOptions()
                {
                    BacklogPolicy      = BacklogPolicy.FailFast,
                    AbortOnConnectFail = false,
                    ConnectTimeout     = 1000,
                    ConnectRetry       = 2,
                    SyncTimeout        = 10000,
                    KeepAlive          = 10000,
                    AsyncTimeout       = 5000,
                    AllowAdmin         = true,
                };
                options.EndPoints.Add(TestConfig.Current.PrimaryServerAndPort);

                using var muxer = await ConnectionMultiplexer.ConnectAsync(options, Writer);

                var db = muxer.GetDatabase();
                Writer.WriteLine("Test: Initial (connected) ping");
                await db.PingAsync();

                var server = muxer.GetServerSnapshot()[0];
                var stats  = server.GetBridgeStatus(ConnectionType.Interactive);
                Assert.Equal(0, stats.BacklogMessagesPending); // Everything's normal

                // Fail the connection
                Writer.WriteLine("Test: Simulating failure");
                muxer.AllowConnect = false;
                server.SimulateConnectionFailure(SimulatedFailureType.All);
                Assert.False(muxer.IsConnected);

                // Queue up some commands
                Writer.WriteLine("Test: Disconnected pings");
                await Assert.ThrowsAsync <RedisConnectionException>(() => db.PingAsync());

                var disconnectedStats = server.GetBridgeStatus(ConnectionType.Interactive);
                Assert.False(muxer.IsConnected);
                Assert.Equal(0, disconnectedStats.BacklogMessagesPending);

                Writer.WriteLine("Test: Allowing reconnect");
                muxer.AllowConnect = true;
                Writer.WriteLine("Test: Awaiting reconnect");
                await UntilConditionAsync(TimeSpan.FromSeconds(3), () => muxer.IsConnected).ForAwait();

                Writer.WriteLine("Test: Reconnecting");
                Assert.True(muxer.IsConnected);
                Assert.True(server.IsConnected);
                var reconnectedStats = server.GetBridgeStatus(ConnectionType.Interactive);
                Assert.Equal(0, reconnectedStats.BacklogMessagesPending);

                _ = db.PingAsync();
                _ = db.PingAsync();
                var lastPing = db.PingAsync();

                // For debug, print out the snapshot and server states
                PrintSnapshot(muxer);

                Assert.NotNull(muxer.SelectServer(Message.Create(-1, CommandFlags.None, RedisCommand.PING)));

                // We should see none queued
                Assert.Equal(0, stats.BacklogMessagesPending);
                await lastPing;
            }
            finally
            {
                ClearAmbientFailures();
            }
        }
        public async Task QueuesAndFlushesAfterReconnecting()
        {
            try
            {
                var options = new ConfigurationOptions()
                {
                    BacklogPolicy      = BacklogPolicy.Default,
                    AbortOnConnectFail = false,
                    ConnectTimeout     = 1000,
                    ConnectRetry       = 2,
                    SyncTimeout        = 10000,
                    KeepAlive          = 10000,
                    AsyncTimeout       = 5000,
                    AllowAdmin         = true,
                    SocketManager      = SocketManager.ThreadPool,
                };
                options.EndPoints.Add(TestConfig.Current.PrimaryServerAndPort);

                using var muxer = await ConnectionMultiplexer.ConnectAsync(options, Writer);

                muxer.ErrorMessage       += (s, e) => Log($"Error Message {e.EndPoint}: {e.Message}");
                muxer.InternalError      += (s, e) => Log($"Internal Error {e.EndPoint}: {e.Exception.Message}");
                muxer.ConnectionFailed   += (s, a) => Log("Disconnected: " + EndPointCollection.ToString(a.EndPoint));
                muxer.ConnectionRestored += (s, a) => Log("Reconnected: " + EndPointCollection.ToString(a.EndPoint));

                var db = muxer.GetDatabase();
                Writer.WriteLine("Test: Initial (connected) ping");
                await db.PingAsync();

                var server = muxer.GetServerSnapshot()[0];
                var stats  = server.GetBridgeStatus(ConnectionType.Interactive);
                Assert.Equal(0, stats.BacklogMessagesPending); // Everything's normal

                // Fail the connection
                Writer.WriteLine("Test: Simulating failure");
                muxer.AllowConnect = false;
                server.SimulateConnectionFailure(SimulatedFailureType.All);
                Assert.False(muxer.IsConnected);

                // Queue up some commands
                Writer.WriteLine("Test: Disconnected pings");

                Task[] pings = new Task[3];
                pings[0] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(1));
                pings[1] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(2));
                pings[2] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(3));
                void disconnectedPings(int id)
                {
                    // No need to delay, we're going to try a disconnected connection immediately so it'll fail...
                    Log($"Pinging (disconnected - {id})");
                    var result = db.Ping();

                    Log($"Pinging (disconnected - {id}) - result: " + result);
                }
                Writer.WriteLine("Test: Disconnected pings issued");

                Assert.False(muxer.IsConnected);
                // Give the tasks time to queue
                await UntilConditionAsync(TimeSpan.FromSeconds(5), () => server.GetBridgeStatus(ConnectionType.Interactive).BacklogMessagesPending >= 3);

                var disconnectedStats = server.GetBridgeStatus(ConnectionType.Interactive);
                Log($"Test Stats: (BacklogMessagesPending: {disconnectedStats.BacklogMessagesPending}, TotalBacklogMessagesQueued: {disconnectedStats.TotalBacklogMessagesQueued})");
                Assert.True(disconnectedStats.BacklogMessagesPending >= 3, $"Expected {nameof(disconnectedStats.BacklogMessagesPending)} > 3, got {disconnectedStats.BacklogMessagesPending}");

                Writer.WriteLine("Test: Allowing reconnect");
                muxer.AllowConnect = true;
                Writer.WriteLine("Test: Awaiting reconnect");
                await UntilConditionAsync(TimeSpan.FromSeconds(3), () => muxer.IsConnected).ForAwait();

                Writer.WriteLine("Test: Checking reconnected 1");
                Assert.True(muxer.IsConnected);

                var afterConnectedStats = server.GetBridgeStatus(ConnectionType.Interactive);
                Writer.WriteLine($"Test: BacklogStatus: {afterConnectedStats.BacklogStatus}, BacklogMessagesPending: {afterConnectedStats.BacklogMessagesPending}, IsWriterActive: {afterConnectedStats.IsWriterActive}, MessagesSinceLastHeartbeat: {afterConnectedStats.MessagesSinceLastHeartbeat}, TotalBacklogMessagesQueued: {afterConnectedStats.TotalBacklogMessagesQueued}");

                Writer.WriteLine("Test: Awaiting 3 pings");
                await Task.WhenAll(pings);

                Writer.WriteLine("Test: Checking reconnected 2");
                Assert.True(muxer.IsConnected);
                var reconnectedStats = server.GetBridgeStatus(ConnectionType.Interactive);
                Assert.Equal(0, reconnectedStats.BacklogMessagesPending);

                Writer.WriteLine("Test: Pinging again...");
                pings[0] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(4));
                pings[1] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(5));
                pings[2] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(6));
                Writer.WriteLine("Test: Last Ping queued");

                // We should see none queued
                Writer.WriteLine("Test: BacklogMessagesPending check");
                Assert.Equal(0, stats.BacklogMessagesPending);
                Writer.WriteLine("Test: Awaiting 3 more pings");
                await Task.WhenAll(pings);

                Writer.WriteLine("Test: Done");
            }
            finally
            {
                ClearAmbientFailures();
            }
        }
Example #10
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await this.StopAsync(CancellationToken.None);

            this._connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(this.Options.Configuration);
        }
        public async Task QueuesAndFlushesAfterReconnectingAsync()
        {
            try
            {
                var options = new ConfigurationOptions()
                {
                    BacklogPolicy      = BacklogPolicy.Default,
                    AbortOnConnectFail = false,
                    ConnectTimeout     = 1000,
                    ConnectRetry       = 2,
                    SyncTimeout        = 10000,
                    KeepAlive          = 10000,
                    AsyncTimeout       = 5000,
                    AllowAdmin         = true,
                    SocketManager      = SocketManager.ThreadPool,
                };
                options.EndPoints.Add(TestConfig.Current.PrimaryServerAndPort);

                using var muxer = await ConnectionMultiplexer.ConnectAsync(options, Writer);

                muxer.ErrorMessage       += (s, e) => Log($"Error Message {e.EndPoint}: {e.Message}");
                muxer.InternalError      += (s, e) => Log($"Internal Error {e.EndPoint}: {e.Exception.Message}");
                muxer.ConnectionFailed   += (s, a) => Log("Disconnected: " + EndPointCollection.ToString(a.EndPoint));
                muxer.ConnectionRestored += (s, a) => Log("Reconnected: " + EndPointCollection.ToString(a.EndPoint));

                var db = muxer.GetDatabase();
                Writer.WriteLine("Test: Initial (connected) ping");
                await db.PingAsync();

                var server = muxer.GetServerSnapshot()[0];
                var stats  = server.GetBridgeStatus(ConnectionType.Interactive);
                Assert.Equal(0, stats.BacklogMessagesPending); // Everything's normal

                // Fail the connection
                Writer.WriteLine("Test: Simulating failure");
                muxer.AllowConnect = false;
                server.SimulateConnectionFailure(SimulatedFailureType.All);
                Assert.False(muxer.IsConnected);

                // Queue up some commands
                Writer.WriteLine("Test: Disconnected pings");
                var ignoredA = db.PingAsync();
                var ignoredB = db.PingAsync();
                var lastPing = db.PingAsync();

                // TODO: Add specific server call

                var disconnectedStats = server.GetBridgeStatus(ConnectionType.Interactive);
                Assert.False(muxer.IsConnected);
                Assert.True(disconnectedStats.BacklogMessagesPending >= 3, $"Expected {nameof(disconnectedStats.BacklogMessagesPending)} > 3, got {disconnectedStats.BacklogMessagesPending}");

                Writer.WriteLine("Test: Allowing reconnect");
                muxer.AllowConnect = true;
                Writer.WriteLine("Test: Awaiting reconnect");
                await UntilConditionAsync(TimeSpan.FromSeconds(3), () => muxer.IsConnected).ForAwait();

                Writer.WriteLine("Test: Checking reconnected 1");
                Assert.True(muxer.IsConnected);

                Writer.WriteLine("Test: ignoredA Status: " + ignoredA.Status);
                Writer.WriteLine("Test: ignoredB Status: " + ignoredB.Status);
                Writer.WriteLine("Test: lastPing Status: " + lastPing.Status);
                var afterConnectedStats = server.GetBridgeStatus(ConnectionType.Interactive);
                Writer.WriteLine($"Test: BacklogStatus: {afterConnectedStats.BacklogStatus}, BacklogMessagesPending: {afterConnectedStats.BacklogMessagesPending}, IsWriterActive: {afterConnectedStats.IsWriterActive}, MessagesSinceLastHeartbeat: {afterConnectedStats.MessagesSinceLastHeartbeat}, TotalBacklogMessagesQueued: {afterConnectedStats.TotalBacklogMessagesQueued}");

                Writer.WriteLine("Test: Awaiting lastPing 1");
                await lastPing;

                Writer.WriteLine("Test: Checking reconnected 2");
                Assert.True(muxer.IsConnected);
                var reconnectedStats = server.GetBridgeStatus(ConnectionType.Interactive);
                Assert.Equal(0, reconnectedStats.BacklogMessagesPending);

                Writer.WriteLine("Test: Pinging again...");
                _ = db.PingAsync();
                _ = db.PingAsync();
                Writer.WriteLine("Test: Last Ping issued");
                lastPing = db.PingAsync();

                // We should see none queued
                Writer.WriteLine("Test: BacklogMessagesPending check");
                Assert.Equal(0, stats.BacklogMessagesPending);
                Writer.WriteLine("Test: Awaiting lastPing 2");
                await lastPing;
                Writer.WriteLine("Test: Done");
            }
            finally
            {
                ClearAmbientFailures();
            }
        }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy(Cors,
                                  builder =>
                {
                    builder
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowAnyOrigin();
                });
                options.AddPolicy("signalRCors",
                                  builder =>
                {
                    builder
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .WithOrigins("http://localhost:3000",
                                 "https://develop.delegate-market.nl",
                                 "https://delegate-market.nl")
                    .AllowCredentials();
                });
            });

            // configure strongly typed settings objects
            var jwtSettingsSection = Configuration.GetSection("JwtSettings");

            services.Configure <JwtSettings>(jwtSettingsSection);

            // configure jwt authentication
            var jwtSettings = jwtSettingsSection.Get <JwtSettings>();
            var key         = Encoding.ASCII.GetBytes(jwtSettings.SecretJWT);

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata      = false;
                x.SaveToken                 = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey         = new SymmetricSecurityKey(key),
                    ValidateIssuer           = false,
                    ValidateAudience         = false,
                    ValidateLifetime         = true,
                };
                x.Events = new JwtBearerEvents()
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];

                        var path = context.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/chathub")))
                        {
                            context.Token = accessToken;
                        }

                        return(Task.CompletedTask);
                    }
                };
            });

            services.AddCors();

            services.AddSingleton <ILiveChatService, LiveChatService>();
            services.AddSingleton <IUserIdProvider, UserIdProvider>();


            //jwt get id from token helper
            services.AddTransient <IJwtIdClaimReaderHelper, JwtIdClaimReaderHelper>();

            services.AddTransient <IChatService, ChatService>();

            services.AddTransient <IChatRepository, ChatRepository>();

            services.Configure <ChatDatabaseSettings>(
                Configuration.GetSection(nameof(ChatDatabaseSettings)));

            services.AddSingleton <IChatDatabaseSettings>(sp =>
                                                          sp.GetRequiredService <IOptions <ChatDatabaseSettings> >().Value);

            services.AddControllers();
            services.AddSignalR().AddStackExchangeRedis(o => o.ConnectionFactory = async writer =>
            {
                var config = new ConfigurationOptions
                {
                    AbortOnConnectFail = false
                };
                config.EndPoints.Add(Configuration["HubSettings:Url"]);
                config.SetDefaultPorts();
                var connection = await ConnectionMultiplexer.ConnectAsync(config, writer);
                return(connection);
            });

            services.AddHealthChecks().AddCheck("healthy", () => HealthCheckResult.Healthy());
        }
Example #13
0
        public ConnectionMultiplexer GetConnection()
        {
            if (_connection == null || !_connection.IsConnected)
            {
                lock (_connectionLock)
                {
                    if (_connection != null && _connection.IsConnected)
                    {
                        return(_connection);
                    }
                    if (_connection != null)
                    {
                        _connection.Close(false);
                        _connection.Dispose();
                        _connection = null;
                    }

                    var  tryCount = 0;
                    bool allowRetry;
                    do
                    {
                        allowRetry = false;
                        try
                        {
                            var sw      = Stopwatch.StartNew();
                            var innerSw = Stopwatch.StartNew();
                            try
                            {
                                // Sometimes ConnectionMultiplexer.Connect is failed and issue does not solved https://github.com/StackExchange/StackExchange.Redis/issues/42
                                // I've created manualy Connect and control timeout.
                                // I recommend set connectTimeout from 1000 to 5000. (configure your network latency)
                                var tcs           = new System.Threading.Tasks.TaskCompletionSource <ConnectionMultiplexer>();
                                var connectThread = new Thread(_ =>
                                {
                                    try
                                    {
                                        var connTask = ConnectionMultiplexer.ConnectAsync(_configuration, _connectionMultiplexerLog)
                                                       .ContinueWith(x =>
                                        {
                                            innerSw.Stop();
                                            if (x.IsCompleted)
                                            {
                                                if (!tcs.TrySetResult(x.Result))
                                                {
                                                    // already faulted
                                                    x.Result.Close(false);
                                                    x.Result.Dispose();
                                                }
                                            }
                                        });
                                        if (!connTask.Wait(this._configuration.ConnectTimeout))
                                        {
                                            tcs.TrySetException(new TimeoutException("Redis Connect Timeout. Elapsed:" + sw.Elapsed.TotalMilliseconds + "ms"));
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        tcs.TrySetException(ex);
                                    }
                                });
                                connectThread.Start();

                                _connection = tcs.Task.GetAwaiter().GetResult();
                                _connection.IncludeDetailInExceptions = true;
                                sw.Stop();
                            }
                            catch (Exception)
                            {
                                sw.Stop();
                                _connection = null;
                            }
                        }
                        catch (TimeoutException)
                        {
                            tryCount++;
                            allowRetry = true;
                        }
                    } while (_connection == null && allowRetry);
                }
            }

            return(_connection);
        }
Example #14
0
        public async Task LoadServicesAsync(MikiAppBuilder app)
        {
            var cache = new StackExchangeCacheClient(
                new ProtobufSerializer(),
                await ConnectionMultiplexer.ConnectAsync(Global.Config.RedisConnectionString)
                );

            app.AddSingletonService <ICacheClient>(cache);
            app.AddSingletonService <IExtendedCacheClient>(cache);
            app.Services.AddDbContext <DbContext, MikiContext>(x => x.UseNpgsql(Global.Config.ConnString));

            app.AddSingletonService(new LoggingService());

            if (!string.IsNullOrWhiteSpace(Global.Config.MikiApiBaseUrl) && !string.IsNullOrWhiteSpace(Global.Config.MikiApiKey))
            {
                app.AddSingletonService(new MikiApiClient(Global.Config.MikiApiKey));
            }
            else
            {
                Log.Warning("No Miki API parameters were supplied, ignoring Miki API.");
            }

            app.AddSingletonService <IApiClient>(new DiscordApiClient(Global.Config.Token, cache));

            if (Global.Config.SelfHosted)
            {
                var gatewayConfig = GatewayConfiguration.Default();
                gatewayConfig.ShardCount      = 1;
                gatewayConfig.ShardId         = 0;
                gatewayConfig.Token           = Global.Config.Token;
                gatewayConfig.WebSocketClient = new BasicWebSocketClient();
                app.AddSingletonService <IGateway>(new CentralizedGatewayShard(gatewayConfig));
            }
            else
            {
                app.AddSingletonService <IGateway>(new DistributedGateway(new MessageClientConfiguration
                {
                    ConnectionString = new Uri(Global.Config.RabbitUrl.ToString()),
                    QueueName        = "gateway",
                    ExchangeName     = "consumer",
                    ConsumerAutoAck  = false,
                    PrefetchCount    = 25
                }));
            }

            app.AddSingletonService(new UrbanDictionaryAPI());
            app.AddSingletonService(new BunnyCDNClient(Global.Config.BunnyCdnKey));
            app.AddSingletonService(new ConfigurationManager());
            app.AddSingletonService(new EventSystem(new EventSystemConfig()
            {
                Developers = Global.Config.DeveloperIds,
            }));

            app.AddSingletonService(new BackgroundStore());

            if (!string.IsNullOrWhiteSpace(Global.Config.SharpRavenKey))
            {
                app.AddSingletonService(new RavenClient(Global.Config.SharpRavenKey));
            }
            else
            {
                Log.Warning("Sentry.io key not provided, ignoring distributed error logging...");
            }
        }
        public async Task <IDatabase> Get()
        {
            var connection = await ConnectionMultiplexer.ConnectAsync(_cacheOptions.ConnectionString);

            return(connection.GetDatabase());
        }
Example #16
0
 public RedisClient(string connectionString, TelemetryClient telemetryClient)
 {
     _connection      = new AsyncLazy <ConnectionMultiplexer>(() => ConnectionMultiplexer.ConnectAsync(connectionString));
     _telemetryClient = telemetryClient;
 }
Example #17
0
 static RedisClient()
 {
     _CONN = ConnectionMultiplexer.ConnectAsync("localhost").ConfigureAwait(false).GetAwaiter().GetResult();
 }
        public async Task ManagedPrimaryConnectionEndToEndWithFailoverTest()
        {
            var connectionString = $"{TestConfig.Current.SentinelServer}:{TestConfig.Current.SentinelPortA},serviceName={ServiceOptions.ServiceName},allowAdmin=true";
            var conn             = await ConnectionMultiplexer.ConnectAsync(connectionString);

            conn.ConfigurationChanged += (s, e) => Log($"Configuration changed: {e.EndPoint}");
            var sub = conn.GetSubscriber();

            sub.Subscribe("*", (channel, message) => Log($"Sub: {channel}, message:{message}"));

            var db = conn.GetDatabase();
            await db.PingAsync();

            var endpoints = conn.GetEndPoints();

            Assert.Equal(2, endpoints.Length);

            var servers = endpoints.Select(e => conn.GetServer(e)).ToArray();

            Assert.Equal(2, servers.Length);

            var primary = servers.FirstOrDefault(s => !s.IsReplica);

            Assert.NotNull(primary);
            var replica = servers.FirstOrDefault(s => s.IsReplica);

            Assert.NotNull(replica);
            Assert.NotEqual(primary.EndPoint.ToString(), replica.EndPoint.ToString());

            // Set string value on current primary
            var expected = DateTime.Now.Ticks.ToString();

            Log("Tick Key: " + expected);
            var key = Me();
            await db.KeyDeleteAsync(key, CommandFlags.FireAndForget);

            await db.StringSetAsync(key, expected);

            var value = await db.StringGetAsync(key);

            Assert.Equal(expected, value);

            Log("Waiting for first replication check...");
            // force read from replica, replication has some lag
            await WaitForReplicationAsync(servers[0]).ForAwait();

            value = await db.StringGetAsync(key, CommandFlags.DemandReplica);

            Assert.Equal(expected, value);

            Log("Waiting for ready pre-failover...");
            await WaitForReadyAsync();

            // capture current replica
            var replicas = SentinelServerA.SentinelGetReplicaAddresses(ServiceName);

            Log("Starting failover...");
            var sw = Stopwatch.StartNew();

            SentinelServerA.SentinelFailover(ServiceName);

            // There's no point in doing much for 10 seconds - this is a built-in delay of how Sentinel works.
            // The actual completion invoking the replication of the former primary is handled via
            // https://github.com/redis/redis/blob/f233c4c59d24828c77eb1118f837eaee14695f7f/src/sentinel.c#L4799-L4808
            // ...which is invoked by INFO polls every 10 seconds (https://github.com/redis/redis/blob/f233c4c59d24828c77eb1118f837eaee14695f7f/src/sentinel.c#L81)
            // ...which is calling https://github.com/redis/redis/blob/f233c4c59d24828c77eb1118f837eaee14695f7f/src/sentinel.c#L2666
            // However, the quicker iteration on INFO during an o_down does not apply here: https://github.com/redis/redis/blob/f233c4c59d24828c77eb1118f837eaee14695f7f/src/sentinel.c#L3089-L3104
            // So...we're waiting 10 seconds, no matter what. Might as well just idle to be more stable.
            await Task.Delay(TimeSpan.FromSeconds(10));

            // wait until the replica becomes the primary
            Log("Waiting for ready post-failover...");
            await WaitForReadyAsync(expectedPrimary : replicas[0]);

            Log($"Time to failover: {sw.Elapsed}");

            endpoints = conn.GetEndPoints();
            Assert.Equal(2, endpoints.Length);

            servers = endpoints.Select(e => conn.GetServer(e)).ToArray();
            Assert.Equal(2, servers.Length);

            var newPrimary = servers.FirstOrDefault(s => !s.IsReplica);

            Assert.NotNull(newPrimary);
            Assert.Equal(replica.EndPoint.ToString(), newPrimary.EndPoint.ToString());
            var newReplica = servers.FirstOrDefault(s => s.IsReplica);

            Assert.NotNull(newReplica);
            Assert.Equal(primary.EndPoint.ToString(), newReplica.EndPoint.ToString());
            Assert.NotEqual(primary.EndPoint.ToString(), replica.EndPoint.ToString());

            value = await db.StringGetAsync(key);

            Assert.Equal(expected, value);

            Log("Waiting for second replication check...");
            // force read from replica, replication has some lag
            await WaitForReplicationAsync(newPrimary).ForAwait();

            value = await db.StringGetAsync(key, CommandFlags.DemandReplica);

            Assert.Equal(expected, value);
        }
        public async Task Start()
        {
            _multiplexer = await ConnectionMultiplexer.ConnectAsync(_connectionString);

            _redis = _multiplexer.GetDatabase();
        }
Example #20
0
        public async Task Capture_Redis_Commands_On_Transaction()
        {
            var containerBuilder = new TestcontainersBuilder <RedisTestcontainer>()
                                   .WithDatabase(new RedisTestcontainerConfiguration());

            await using var container = containerBuilder.Build();
            await container.StartAsync();

            var connection = await ConnectionMultiplexer.ConnectAsync(container.ConnectionString);

            var count = 0;

            while (!connection.IsConnected)
            {
                if (count < 5)
                {
                    count++;
                    await Task.Delay(500);
                }
                else
                {
                    throw new Exception("Could not connect to redis for integration test");
                }
            }

            var payloadSender    = new MockPayloadSender();
            var transactionCount = 2;

            using var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender));
            connection.UseElasticApm(agent);

            for (var i = 0; i < transactionCount; i++)
            {
                await agent.Tracer.CaptureTransaction("Set and Get String", ApiConstants.TypeDb, async() =>
                {
                    var database = connection.GetDatabase();
                    await database.StringSetAsync($"string{i}", i);
                    await database.StringGetAsync($"string{i}");
                    await database.StringSetAsync($"string{i}", i);
                    await database.StringGetAsync($"string{i}");

                    // fire and forget commands may not end up being captured before transaction end is
                    // called and profiling session is finished
                    await database.StringSetAsync($"string{i}", i, flags: CommandFlags.FireAndForget);
                    await database.StringGetAsync($"string{i}", CommandFlags.FireAndForget);
                });
            }

            var transactions = payloadSender.Transactions;

            transactions.Should().HaveCount(transactionCount);

            var minSpansPerTransaction = 4;

            payloadSender.Spans.Should().HaveCountGreaterOrEqualTo(transactionCount * minSpansPerTransaction);

            foreach (var transaction in transactions)
            {
                payloadSender.Spans.Count(s => s.TransactionId == transaction.Id).Should().BeGreaterOrEqualTo(minSpansPerTransaction);
            }

            await container.StopAsync();
        }
Example #21
0
        public static ConnectionMultiplexer CreateDefault(
            TextWriter output,
            string clientName    = null, int?syncTimeout           = null, bool?allowAdmin          = null, int?keepAlive  = null,
            int?connectTimeout   = null, string password           = null, string tieBreaker        = null, TextWriter log = null,
            bool fail            = true, string[] disabledCommands = null, string[] enabledCommands = null,
            bool checkConnect    = true, string failMessage        = null,
            string channelPrefix = null, Proxy?proxy               = null,
            string configuration = null, bool logTransactionData   = true,

            [CallerMemberName] string caller = null)
        {
            StringWriter localLog = null;

            if (log == null)
            {
                log = localLog = new StringWriter();
            }
            try
            {
                var config = ConfigurationOptions.Parse(configuration);
                if (disabledCommands != null && disabledCommands.Length != 0)
                {
                    config.CommandMap = CommandMap.Create(new HashSet <string>(disabledCommands), false);
                }
                else if (enabledCommands != null && enabledCommands.Length != 0)
                {
                    config.CommandMap = CommandMap.Create(new HashSet <string>(enabledCommands), true);
                }

                if (Debugger.IsAttached)
                {
                    syncTimeout = int.MaxValue;
                }

                if (channelPrefix != null)
                {
                    config.ChannelPrefix = channelPrefix;
                }
                if (tieBreaker != null)
                {
                    config.TieBreaker = tieBreaker;
                }
                if (password != null)
                {
                    config.Password = string.IsNullOrEmpty(password) ? null : password;
                }
                if (clientName != null)
                {
                    config.ClientName = clientName;
                }
                else if (caller != null)
                {
                    config.ClientName = caller;
                }
                if (syncTimeout != null)
                {
                    config.SyncTimeout = syncTimeout.Value;
                }
                if (allowAdmin != null)
                {
                    config.AllowAdmin = allowAdmin.Value;
                }
                if (keepAlive != null)
                {
                    config.KeepAlive = keepAlive.Value;
                }
                if (connectTimeout != null)
                {
                    config.ConnectTimeout = connectTimeout.Value;
                }
                if (proxy != null)
                {
                    config.Proxy = proxy.Value;
                }
                var watch = Stopwatch.StartNew();
                var task  = ConnectionMultiplexer.ConnectAsync(config, log);
                if (!task.Wait(config.ConnectTimeout >= (int.MaxValue / 2) ? int.MaxValue : config.ConnectTimeout * 2))
                {
                    task.ContinueWith(x =>
                    {
                        try
                        {
                            GC.KeepAlive(x.Exception);
                        }
                        catch
                        { }
                    }, TaskContinuationOptions.OnlyOnFaulted);
                    throw new TimeoutException("Connect timeout");
                }
                watch.Stop();
                if (output != null)
                {
                    Log(output, "Connect took: " + watch.ElapsedMilliseconds + "ms");
                }
                var muxer = task.Result;
                if (checkConnect && (muxer == null || !muxer.IsConnected))
                {
                    // If fail is true, we throw.
                    Assert.False(fail, failMessage + "Server is not available");
                    Skip.Inconclusive(failMessage + "Server is not available");
                }
                if (output != null)
                {
                    muxer.MessageFaulted += (msg, ex, origin) =>
                    {
                        output?.WriteLine($"Faulted from '{origin}': '{msg}' - '{(ex == null ? "(null)" : ex.Message)}'");
                        if (ex != null && ex.Data.Contains("got"))
                        {
                            output?.WriteLine($"Got: '{ex.Data["got"]}'");
                        }
                    };
                    muxer.Connecting += (e, t) => output?.WriteLine($"Connecting to {Format.ToString(e)} as {t}");
                    if (logTransactionData)
                    {
                        muxer.TransactionLog += msg => output?.WriteLine("tran: " + msg);
                    }
                    muxer.InfoMessage  += msg => output?.WriteLine(msg);
                    muxer.Resurrecting += (e, t) => output?.WriteLine($"Resurrecting {Format.ToString(e)} as {t}");
                    muxer.Closing      += complete => output?.WriteLine(complete ? "Closed" : "Closing...");
                }
                return(muxer);
            }
            catch
            {
                if (localLog != null)
                {
                    output?.WriteLine(localLog.ToString());
                }
                throw;
            }
        }
Example #22
0
        public async Task Capture_Redis_Commands_On_Span()
        {
            var containerBuilder = new TestcontainersBuilder <RedisTestcontainer>()
                                   .WithDatabase(new RedisTestcontainerConfiguration());

            await using var container = containerBuilder.Build();
            await container.StartAsync();

            var connection = await ConnectionMultiplexer.ConnectAsync(container.ConnectionString);

            var count = 0;

            while (!connection.IsConnected)
            {
                if (count < 5)
                {
                    count++;
                    await Task.Delay(500);
                }
                else
                {
                    throw new Exception("Could not connect to redis for integration test");
                }
            }

            var payloadSender    = new MockPayloadSender();
            var transactionCount = 2;

            using var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender));
            connection.UseElasticApm(agent);

            var database = connection.GetDatabase();

            for (var i = 0; i < transactionCount; i++)
            {
                await agent.Tracer.CaptureTransaction($"transaction {i}", ApiConstants.TypeDb, async t =>
                {
                    // span 1
                    await database.StringSetAsync($"string{i}", i);

                    // span 2
                    await database.StringGetAsync($"string{i}");

                    // span 3
                    await t.CaptureSpan($"parent span {i}", ApiConstants.TypeDb, async() =>
                    {
                        // spans 4,5,6,7
                        await database.StringSetAsync($"string{i}", i);
                        await database.StringGetAsync($"string{i}");
                        await database.StringSetAsync($"string{i}", i);
                        await database.StringGetAsync($"string{i}");
                    });
                });
            }

            var transactions = payloadSender.Transactions;

            transactions.Should().HaveCount(transactionCount);

            var spansPerParentSpan  = 4;
            var topLevelSpans       = 3;
            var spansPerTransaction = spansPerParentSpan + topLevelSpans;

            payloadSender.Spans.Should().HaveCount(transactionCount * spansPerTransaction);

            foreach (var transaction in transactions)
            {
                var transactionSpans = payloadSender.Spans
                                       .Where(s => s.TransactionId == transaction.Id)
                                       .ToList();

                transactionSpans.Should().HaveCount(spansPerTransaction);

                var parentSpans = transactionSpans.Where(s => s.ParentId == s.TransactionId).ToList();
                parentSpans.Should().HaveCount(topLevelSpans);

                var parentSpanId = parentSpans.OrderByDescending(s => s.Timestamp).First().Id;
                transactionSpans.Count(s => s.ParentId == parentSpanId).Should().Be(spansPerParentSpan);
            }

            await container.StopAsync();
        }
Example #23
0
 protected async Task <ConnectionMultiplexer> Init()
 {
     return(await ConnectionMultiplexer.ConnectAsync("localhost:6379", (options) => options.Password = "******"));
 }
Example #24
0
        public async Task ManagedMasterConnectionEndToEndWithFailoverTest()
        {
            var connectionString = $"{TestConfig.Current.SentinelServer}:{TestConfig.Current.SentinelPortA},serviceName={ServiceOptions.ServiceName},allowAdmin=true";
            var conn             = await ConnectionMultiplexer.ConnectAsync(connectionString);

            conn.ConfigurationChanged += (s, e) => {
                Log($"Configuration changed: {e.EndPoint}");
            };

            var db = conn.GetDatabase();
            await db.PingAsync();

            var endpoints = conn.GetEndPoints();

            Assert.Equal(2, endpoints.Length);

            var servers = endpoints.Select(e => conn.GetServer(e)).ToArray();

            Assert.Equal(2, servers.Length);

            var master = servers.FirstOrDefault(s => !s.IsReplica);

            Assert.NotNull(master);
            var replica = servers.FirstOrDefault(s => s.IsReplica);

            Assert.NotNull(replica);
            Assert.NotEqual(master.EndPoint.ToString(), replica.EndPoint.ToString());

            // set string value on current master
            var expected = DateTime.Now.Ticks.ToString();

            Log("Tick Key: " + expected);
            var key = Me();
            await db.KeyDeleteAsync(key, CommandFlags.FireAndForget);

            await db.StringSetAsync(key, expected);

            var value = await db.StringGetAsync(key);

            Assert.Equal(expected, value);

            // force read from replica, replication has some lag
            WaitForReplication(servers.First());
            value = await db.StringGetAsync(key, CommandFlags.DemandReplica);

            Assert.Equal(expected, value);

            // forces and verifies failover
            DoFailover();

            endpoints = conn.GetEndPoints();
            Assert.Equal(2, endpoints.Length);

            servers = endpoints.Select(e => conn.GetServer(e)).ToArray();
            Assert.Equal(2, servers.Length);

            var newMaster = servers.FirstOrDefault(s => !s.IsReplica);

            Assert.NotNull(newMaster);
            Assert.Equal(replica.EndPoint.ToString(), newMaster.EndPoint.ToString());
            var newReplica = servers.FirstOrDefault(s => s.IsReplica);

            Assert.NotNull(newReplica);
            Assert.Equal(master.EndPoint.ToString(), newReplica.EndPoint.ToString());
            Assert.NotEqual(master.EndPoint.ToString(), replica.EndPoint.ToString());

            value = await db.StringGetAsync(key);

            Assert.Equal(expected, value);

            // force read from replica, replication has some lag
            WaitForReplication(newMaster);
            value = await db.StringGetAsync(key, CommandFlags.DemandReplica);

            Assert.Equal(expected, value);
        }
        public async Task PerformanceTest(TestClient testClient)
        {
            var tasks = new List <Task>();

            for (var taskCount = 0; taskCount < 5; taskCount++)
            {
                var task = Task.Run(async() =>
                {
                    if (testClient == TestClient.StackExchange)
                    {
                        var stackExchange = (await ConnectionMultiplexer.ConnectAsync(new ConfigurationOptions
                        {
                            EndPoints = { { TestInformation.Host, TestInformation.Port } },
                            Password = TestInformation.Password,
                            Ssl = true
                        })).GetDatabase(0);

                        await stackExchange.StringSetAsync("SingleKey", "123", TimeSpan.FromSeconds(120));

                        for (var outer = 0; outer < 5; outer++)
                        {
                            var stackExchangeRedisClientStopwatch = Stopwatch.StartNew();

                            for (var i = 0; i < 200; i++)
                            {
                                var redisValue = await stackExchange.StringGetAsync("SingleKey");
                            }

                            stackExchangeRedisClientStopwatch.Stop();
                            var stackExchangeRedisClientStopwatchTimeTaken =
                                stackExchangeRedisClientStopwatch.ElapsedMilliseconds;
                            Console.WriteLine($"Time Taken: {stackExchangeRedisClientStopwatchTimeTaken} ms");
                        }
                    }
                    else
                    {
                        await(await TomLonghurstRedisClient).StringSetAsync("SingleKey",
                                                                            "123",
                                                                            120,
                                                                            AwaitOptions.AwaitCompletion);

                        for (var outer = 0; outer < 5; outer++)
                        {
                            var tomLonghurstRedisClientStopwatch = Stopwatch.StartNew();

                            for (var i = 0; i < 200; i++)
                            {
                                var redisValue = await(await TomLonghurstRedisClient).StringGetAsync("SingleKey");
                            }

                            tomLonghurstRedisClientStopwatch.Stop();
                            var tomLonghurstRedisClientStopwatchTimeTaken =
                                tomLonghurstRedisClientStopwatch.ElapsedMilliseconds;
                            Console.WriteLine($"Time Taken: {tomLonghurstRedisClientStopwatchTimeTaken} ms");
                        }
                    }
                });

                tasks.Add(task);
            }

            await Task.WhenAll(tasks);
        }
Example #26
0
 public Task <ConnectionMultiplexer> Connect()
 {
     return(ConnectionMultiplexer.ConnectAsync(ConnectionString));
 }
Example #27
0
 private async Task <ConnectionMultiplexer> NewConnection()
 {
     return(await ConnectionMultiplexer.ConnectAsync(connectionString));
 }
Example #28
0
 public Task <ConnectionMultiplexer> Connect(TextWriter log)
 {
     return(ConnectionMultiplexer.ConnectAsync(ConnectionString, log));
 }
 private static async Task <IConnectionMultiplexer> GetConnectionMultiplexerAsync(ConfigurationOptions options)
 {
     return(await ConnectionMultiplexer.ConnectAsync(options));
 }
Example #30
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddOptions();

            services.AddControllers();

            services.AddMvc(config =>
            {
                config.Filters.Add(new ProducesAttribute("application/json"));
                //config.Filters.Add(new ConsumesAttribute("application/json"));
            })
            .AddFluentValidation()
            .AddJsonOptions(x =>
            {
                x.JsonSerializerOptions.WriteIndented = false;
                x.JsonSerializerOptions.PropertyNameCaseInsensitive = false;
                x.JsonSerializerOptions.IgnoreNullValues            = false;
            });

            services.Configure <GzipCompressionProviderOptions>(options => options.Level = CompressionLevel.Optimal);

            services.AddResponseCompression(options => options.Providers.Add <GzipCompressionProvider>());

            services.AddSignalR()
            .AddJsonProtocol(x =>
            {
                x.PayloadSerializerOptions.IgnoreNullValues            = false;
                x.PayloadSerializerOptions.PropertyNameCaseInsensitive = false;
                x.PayloadSerializerOptions.WriteIndented = false;
            })
            .AddMessagePackProtocol()
            .AddStackExchangeRedis(o =>
            {
                o.ConnectionFactory = async writer =>
                {
                    var config = new StackExchange.Redis.ConfigurationOptions
                    {
                        AbortOnConnectFail = false,
                        ResolveDns         = true
                    };

                    config.EndPoints.Add(Configuration.GetConnectionString("Redis"), 6379);
                    config.SetDefaultPorts();
                    var connection = await ConnectionMultiplexer.ConnectAsync(config, writer);
                    connection.ConnectionFailed += (_, e) =>
                    {
                        Console.WriteLine("Connection to Redis failed.");
                    };

                    if (!connection.IsConnected)
                    {
                        Console.WriteLine("Did not connect to Redis.");
                    }

                    return(connection);
                };
            });

            services.AddCors();

            services.AddEntityFrameworkSqlServer()
            .AddDbContext <ChatContext>((serviceProvider, options) =>
            {
                options.UseApplicationServiceProvider(serviceProvider);
                options.UseInternalServiceProvider(serviceProvider);
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
            });

            services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped <ChatContext>();

            // Health Checks
            services.AddHealthChecks()
            .AddSqlServer(Configuration.GetConnectionString("DefaultConnection"), name: "MSSQL")
            .AddRedis(Configuration.GetConnectionString("Redis"), name: "REDIS");

            services
            .AddHealthChecksUI();

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo {
                    Title = "Chat API", Version = "v1"
                });
                c.EnableAnnotations();
            });
        }