the following Redis Connection Exception occurs from the GetSentinelMasterConnection function when we use Redis.
the exception
(Sentinel: Failed connecting to configured master for service: my master)
and
(Sentinel: The ConnectionMultiplexer is not a Sentinel connection
)
the code of GetSentinelMasterConnection function :
public ConnectionMultiplexer
GetSentinelMasterConnection(ConfigurationOptions config,
TextWriter
log = null)
{
if (ServerSelectionStrategy.ServerType !=
ServerType.Sentinel)
throw new RedisConnectionException(ConnectionFailureType.UnableToConnect,
"Sentinel: The ConnectionMultiplexer is not a Sentinel connection. Detected as: " + ServerSelectionStrategy.ServerType);
if (string.IsNullOrEmpty(config.ServiceName))
throw new ArgumentException("A ServiceName must be specified.");
lock (sentinelConnectionChildren)
{
if (sentinelConnectionChildren.TryGetValue(config.ServiceName, out var sentinelConnectionChild) && !sentinelConnectionChild.IsDisposed)
return sentinelConnectionChild;
}
bool success = false;
ConnectionMultiplexer connection = null;
var sw = Stopwatch.StartNew();
do
{
// Get an initial endpoint - try twice
EndPoint newMasterEndPoint = GetConfiguredMasterForService(config.ServiceName)
?? GetConfiguredMasterForService(config.ServiceName);
if (newMasterEndPoint == null)
{
throw new RedisConnectionException(ConnectionFailureType.UnableToConnect,
$"Sentinel: Failed connecting to configured master for service: {config.ServiceName}");
}
EndPoint[] replicaEndPoints = GetReplicasForService(config.ServiceName)
?? GetReplicasForService(config.ServiceName);
// Replace the master endpoint, if we found another one
// If not, assume the last state is the best we have and minimize the race
if (config.EndPoints.Count == 1)
{
config.EndPoints[0] = newMasterEndPoint;
}
else
{
config.EndPoints.Clear();
config.EndPoints.TryAdd(newMasterEndPoint);
}
foreach (var replicaEndPoint in replicaEndPoints)
{
config.EndPoints.TryAdd(replicaEndPoint);
}
connection = ConnectImpl(config, log);
// verify role is master according to:
// https://redis.io/topics/sentinel-clients
if (connection.GetServer(newMasterEndPoint)?.Role().Value == RedisLiterals.master)
{
success = true;
break;
}
Thread.Sleep(100);
} while (sw.ElapsedMilliseconds < config.ConnectTimeout);
if (!success)
{
throw new RedisConnectionException(ConnectionFailureType.UnableToConnect,
$"Sentinel: Failed connecting to configured master for service: {config.ServiceName}");
}
// Attach to reconnect event to ensure proper connection to the new master
connection.ConnectionRestored += OnManagedConnectionRestored;
// If we lost the connection, run a switch to a least try and get updated info about the master
connection.ConnectionFailed += OnManagedConnectionFailed;
lock (sentinelConnectionChildren)
{
sentinelConnectionChildren[connection.RawConfig.ServiceName] = connection;
}
// Perform the initial switchover
SwitchMaster(RawConfig.EndPoints[0], connection, log);
return connection;
}
Related
I have this issue in production with MySQL connections where the connection is either being used or it's not opened error comes up frequently. I think when multiple requests hit the method then this issue is happening. I got stats from production were 80 different instances hit the Graphql method. I am using Sqlkata to make DB calls. When there are no parallel calls then it works fine.
ConnectionManager.cs
public IDbConnection GetConnection
{
get
{
if (_iDbConnection != null)
{
if (_iDbConnection.State != ConnectionState.Open)
{
_iDbConnection.Open();
return _iDbConnection;
}
}
if (_iDbConnection != null && _iDbConnection.State == ConnectionState.Open)
{
// close the previous connection
_iDbConnection.Close();
// open new connection
_iDbConnection.Open();
return _iDbConnection;
}
try
{
string connectionString = Configuration.GetConnectionString("seasonal");
// Register the factory
DbProviderFactories.RegisterFactory("MySqlConnector", MySqlConnectorFactory.Instance);
// Get the provider invariant names
IEnumerable<string> invariants = DbProviderFactories.GetProviderInvariantNames();
var factory = DbProviderFactories.GetFactory(invariants.FirstOrDefault());
var conn = factory.CreateConnection();
if (conn != null)
{
conn.ConnectionString = connectionString;
conn.Open();
_iDbConnection = conn;
}
}
catch (Exception e)
{
throw;
}
return _iDbConnection;
}
}
Service (constructor)
public OutboundRecordService(IConnectionManager connectionManager) : base(connectionManager)
{
IDbConnection connection = connectionManager.GetConnection;
if (connection.State != ConnectionState.Open)
{
_logger.Error($"Connection is not open, current state: {connection.State}");
}
_queryFactory = new QueryFactory(connection, new MySqlCompiler());
_logger = LogManager.GetLogger(typeof(OutboundRecordService<T>));
}
public async Task<CareMetx.Service.Models.PaginationResult<OutboundRecord>> GetAllByCriteria(OutboundRecordSearchCriteria searchCriteria)
{
try
{
// START - Test code
var arrayTask = new List<Task>();
int i = 10;
for (int c = 0; c < i; c++)
{
arrayTask.Add(Task.Factory.StartNew(() => GetDataFromDB(searchCriteria)));
}
Task.WaitAll(arrayTask.ToArray());
Console.WriteLine("All threads complete");
return await Task.FromResult<CareMetx.Service.Models.PaginationResult<OutboundRecord>>(null);
// END - Test code
}
catch (Exception ex)
{
var message = ex.Message;
}
return null;
}
private async Task<List<OutboundRecord>> GetDataFromDB(OutboundRecordSearchCriteria searchCriteria)
{
Query dbQuery = _queryFactory.Query("SELECT * FROM OutboundRecords Where BatchId = 1");
// Clone the query and get the total count
var totalCountQuery = dbQuery.Clone();
totalCountQuery = totalCountQuery.AsCount();
// Log Record Count SQL
LogSqlQuery(totalCountQuery);
// Get the total record count
var totalRecords = await totalCountQuery.FirstOrDefaultAsync<int>();
}
Exception
I have a Lambda function in AWS (.NET Core) created to sweep Parameter Store parameters from Simple Systems Management into Memcached for easy / fast access by my serverless application. Despite my configuration function using the 'using' syntax for the Memcached client (which I expected to mean the connection would be released from the cache once the work was done) the connection count is continually climbing. My function is triggered once every 60 seconds to sync the parameter values.
Here is what the connection count looks like.
Here is my prototype function code:
public async Task<bool> LcsConfigurationSweeper(ILambdaContext context)
{
try
{
context.Logger.LogLine($"Configuration Sweeper activated");
ElastiCacheClusterConfig config = new ElastiCacheClusterConfig("*******", *******);
using (var client = new MemcachedClient(config))
{
GetParametersByPathRequest getParametersByPathRequest = new GetParametersByPathRequest
{
Recursive = true,
WithDecryption = true,
Path = "***"
};
var getParametersByPathResponse = await _systemsManagementClient.GetParametersByPathAsync(getParametersByPathRequest);
foreach (var parameter in getParametersByPathResponse.Parameters)
{
Object value; // Memcached value
if (client.TryGet(parameter.Name, out value))
{
if (value.ToString() != parameter.Value)
{
context.Logger.LogLine($"Configuration sweeper has detected {parameter.Name} has changed. Updating.");
if (client.Store(Enyim.Caching.Memcached.StoreMode.Replace, parameter.Name, parameter.Value))
{
context.Logger.LogLine($"Parameter {parameter.Name} updated in cache OK.");
return true;
}
else
{
context.Logger.LogLine($"Exception: Parameter {parameter.Name} unable to be updated in cache.");
}
}
}
else
{
if (client.Store(Enyim.Caching.Memcached.StoreMode.Set, parameter.Name, parameter.Value))
{
context.Logger.LogLine($"Parameter {parameter.Name} stored in cache OK.");
return true;
}
else
{
context.Logger.LogLine($"Exception: Parameter {parameter.Name} unable to be stored in cache.");
}
}
}
}
}
catch (Exception ex)
{
context.Logger.LogLine($"Exception: {ex.ToString()}");
}
return false;
}
Good evening everyone, I've got a web app written using .NET and a mobile app.
I'm sending some values to rabbitMQ server through my web app and this is working fine, i put it in a queue but when the mobile app accepts the request, i don't get the returned value.
Here is my controller
public async Task<ActionResult> GetCollect(int id)
{
int PartnerId = 0;
bool SentRequest = false;
try
{
SentRequest = await RuleRabbitMQ.SentRequestRule(id);
if(SentRequest )
{
PartnerId = await RuleRabbitMQ.RequestAccepted();
}
}
catch (Exception Ex)
{
}
}
This is my RabbitMQ class
public class InteractionRabbitMQ
{
public async Task<bool> SentRequestRule(int id)
{
bool ConnectionRabbitMQ = false;
await Task.Run(() =>
{
try
{
ConnectionFactory connectionFactory = new ConnectionFactory()
{
//credentials go here
};
IConnection connection = connectionFactory.CreateConnection();
IModel channel = connection.CreateModel();
channel.QueueDeclare("SolicitacaoSameDay", true, false, false, null);
string rpcResponseQueue = channel.QueueDeclare().QueueName;
string correlationId = Guid.NewGuid().ToString();
IBasicProperties basicProperties = channel.CreateBasicProperties();
basicProperties.ReplyTo = rpcResponseQueue;
basicProperties.CorrelationId = correlationId;
byte[] messageBytes = Encoding.UTF8.GetBytes(string.Concat(" ", id.ToString()));
channel.BasicPublish("", "SolicitacaoSameDay", basicProperties, messageBytes);
channel.Close();
connection.Close();
if (connection != null)
{
ConnectionRabbitMQ = true;
}
else
{
ConnectionRabbitMQ = false;
}
}
catch (Exception Ex)
{
throw new ArgumentException($"Thre was a problem with RabbitMQ server. " +
$"Pleaser, contact the support with Error: {Ex.ToString()}");
}
});
return ConnectionRabbitMQ;
}
public async Task<int> RequestAccepted()
{
bool SearchingPartner= true;
int PartnerId = 0;
await Task.Run(() =>
{
try
{
var connectionFactory = new ConnectionFactory()
{
// credentials
};
IConnection connection = connectionFactory.CreateConnection();
IModel channel = connection.CreateModel();
channel.BasicQos(0, 1, false);
var eventingBasicConsumer = new EventingBasicConsumer(channel);
eventingBasicConsumer.Received += (sender, basicDeliveryEventArgs) =>
{
string Response = Encoding.UTF8.GetString(basicDeliveryEventArgs.Body, 0, basicDeliveryEventArgs.Body.Length);
channel.BasicAck(basicDeliveryEventArgs.DeliveryTag, false);
if(!string.IsNullOrWhiteSpace(Response))
{
int Id = Convert.ToInt32(Response);
PartnerId = Id > 0 ? Id : 0;
SearchingPartner = false;
}
};
channel.BasicConsume("SolicitacaoAceitaSameDay", false, eventingBasicConsumer);
}
catch (Exception Ex)
{
// error message
}
});
return PartnerId ;
}
I am not sure this works, can't build an infrastructure to test this quickly, but - your issue is that the RequestAccepted returns a Task which completes before the Received event is caught by the Rabbit client library.
Syncing the two could possibly resolve the issue, note however that this could potentially make your code waiting very long for (or even - never get) the response.
public Task<int> RequestAccepted()
{
bool SearchingPartner= true;
int PartnerId = 0;
var connectionFactory = new ConnectionFactory()
{
// credentials
};
IConnection connection = connectionFactory.CreateConnection();
IModel channel = connection.CreateModel();
channel.BasicQos(0, 1, false);
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
var eventingBasicConsumer = new EventingBasicConsumer(channel);
eventingBasicConsumer.Received += (sender, basicDeliveryEventArgs) =>
{
string Response = Encoding.UTF8.GetString(basicDeliveryEventArgs.Body, 0, basicDeliveryEventArgs.Body.Length);
channel.BasicAck(basicDeliveryEventArgs.DeliveryTag, false);
if(!string.IsNullOrWhiteSpace(Response))
{
int Id = Convert.ToInt32(Response);
PartnerId = Id > 0 ? Id : 0;
SearchingPartner = false;
tcs.SetResult( PartnerId );
}
};
channel.BasicConsume("SolicitacaoAceitaSameDay", false, eventingBasicConsumer);
return tcs.Task;
}
There are couple of issues with this approach.
First, no error handling.
Then, what if the event is sent by the RMQ before the consumer subscribes to it? The consumer will block as it will never receive anything back.
And last, I don't think RMQ consumers are ever intended to be created in every request to your controller and then never disposed. While this could work on your dev box where you create a couple of requests manually, it won't probably ever scale to fix a scenario where dozens/hundreds of concurrent users hit your website and multiple RMQ consumers compete one against the other.
I don't think there is an easy way around it other than completely separate the consumer out of your web app, put it in a System Service or a Hangfire job and let it get responses to all possible requests and from the cache - serve responses to web requests.
This is a pure speculation, though, based on my understanding of what you try to do. I could be wrong here, of course.
byte[] messageBytes = Encoding.UTF8.GetBytes(string.Concat(" ", idColeta.ToString()));
I reckon 'idColeta' is blank.
How to find whether the user is connecting to the internet using wired?
Here are my current progress
var internetConnectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
if (internetConnectionProfile.GetNetworkConnectivityLevel() == Windows.Networking.Connectivity.NetworkConnectivityLevel.InternetAccess)
{
// has internet connection
}
if (internetConnectionProfile.IsWwanConnectionProfile)
{
// its mobile
}
if (internetConnectionProfile.IsWlanConnectionProfile)
{
// its wireless
}
Try this
bool IsWiredInternetAccess()
{
IReadOnlyList<ConnectionProfile> connections = NetworkInformation.GetConnectionProfiles();
foreach (var connection in connections)
{
if (connection == null) continue;
if (connection.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess)
{
// check is connection wired
if ((connection.ConnectionProfile.IsWlanConnectionProfile)||(connection.IsWwanConnectionProfile))
{
// connection is Wlan or Wwan
return false;
}
else
{
return true;
}
}
}
}
Here is a simple and updated answer
Updated ConnectionProfile class helps to identify ,type of network connection.
ConnectionProfile connectionProfile = NetworkInformation.GetInternetConnectionProfile();
bool isWifi = connectionProfile.IsWlanConnectionProfile;
Here is the scenario
At the start,
Ready Queue : 2
UnAcked: 0
Once the consumer.Queue.Dequeue(1000, out bdea); runs,
ReadyQueue: 1
UnAcked: 1
This is obvious, where we read one message and not Acknowledged yet.
Problem is that when the channel.BasicAck(bdea.DeliveryTag, false); runs,
ReadyQueue: 0
UnAcked: 1
Message which was in the Ready state became UnAcked and ReadyQueue becomes "0" !!
Now, in the while loop, when we look for the second message with consumer.Queue.Dequeue(1000, out bdea);, bdea returns null as there is nothing in the Ready state.
This is the issue, when there an Ack happens, always it drags a message from the Ready queue to UnAck. Therefore the next time I am loosing this UnAcked message which was never dequeued.
But if I stop the process (Console App), UnAck message goes back to Ready State.
Assume there are 10 messages in Ready state at the start, at the end it will only process 5 where you find 5 messages in UnAcked state. Each Ack makes the next message UnAck. If I stop and run again (5 messages in Ready state), guess what, 3 messages will gets processed, 2 will be UnAcked. (Dequeue only picks half of the no of messages)
Here is my code (code which only has the RabbitMQ functionality, issue is there if you try this code as well),
public class TestMessages
{
private ConnectionFactory factory = new ConnectionFactory();
string billingFileId = string.Empty;
private IConnection connection = null;
private IModel channel = null;
public void Listen()
{
try
{
#region CONNECT
factory.AutomaticRecoveryEnabled = true;
factory.UserName = ConfigurationManager.AppSettings["MQUserName"];
factory.Password = ConfigurationManager.AppSettings["MQPassword"];
factory.VirtualHost = ConfigurationManager.AppSettings["MQVirtualHost"];
factory.HostName = ConfigurationManager.AppSettings["MQHostName"];
factory.Port = Convert.ToInt32(ConfigurationManager.AppSettings["MQPort"]);
#endregion
RabbitMQ.Client.Events.BasicDeliverEventArgs bdea;
using (connection = factory.CreateConnection())
{
string jobId = string.Empty;
using (IModel channel = connection.CreateModel())
{
while (true) //KEEP LISTNING
{
if (!channel.IsOpen)
throw new Exception("Channel is closed"); //Exit the loop.
QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
//Prefetch 1 message
channel.BasicQos(0, 1, false);
String consumerTag = channel.BasicConsume(ConfigurationManager.AppSettings["MQQueueName"], false, consumer);
try
{
//Pull out the message
consumer.Queue.Dequeue(1000, out bdea);
if (bdea == null)
{
//Empty Queue
}
else
{
IBasicProperties props = bdea.BasicProperties;
byte[] body = bdea.Body;
string message = System.Text.Encoding.Default.GetString(bdea.Body);
try
{
channel.BasicAck(bdea.DeliveryTag, false);
////Heavy work starts now......
}
catch (Exception ex)
{
//Log
}
}
}
catch (Exception ex)
{
//Log it
}
}
}
}
}
catch (Exception ex)
{
WriteLog.Error(ex);
}
finally
{
//CleanUp();
}
}
}
Am I missing something?
I tried with the "Subscription" rather than the Channel and it works now, clears up the message queue. I referred to this post.
Here is the working code:
public void SubscribeListner()
{
Subscription subscription = null;
const string uploaderExchange = "myQueueExchange";
string queueName = "myQueue";
while (true)
{
try
{
if (subscription == null)
{
try
{
//CONNECT Code
//try to open connection
connection = factory.CreateConnection();
}
catch (BrokerUnreachableException ex)
{
//You probably want to log the error and cancel after N tries,
//otherwise start the loop over to try to connect again after a second or so.
//log.Error(ex);
continue;
}
//crate chanel
channel = connection.CreateModel();
// This instructs the channel not to prefetch more than one message
channel.BasicQos(0, 1, false);
// Create a new, durable exchange
channel.ExchangeDeclare(uploaderExchange, ExchangeType.Direct, true, false, null);
// Create a new, durable queue
channel.QueueDeclare(queueName, true, false, false, null);
// Bind the queue to the exchange
channel.QueueBind(queueName, uploaderExchange, queueName);
//create subscription
subscription = new Subscription(channel, uploaderExchange, false);
}
BasicDeliverEventArgs eventArgs;
var gotMessage = subscription.Next(250, out eventArgs);//250 millisecond
if (gotMessage)
{
if (eventArgs == null)
{
//This means the connection is closed.
//DisposeAllConnectionObjects();
continue;//move to new iterate
}
//process message
subscription.Ack();
//channel.BasicAck(eventArgs.DeliveryTag, false);
}
}
catch (OperationInterruptedException ex)
{
//log.Error(ex);
//DisposeAllConnectionObjects();
}
catch(Exception ex)
{
}
}
}