How to check if connection to Elasticsearch is established? - c#

I want to check if the connection to Elasticsearch database is ok. In other words I want to ping Elasticsearch. When I execute the code below, an exception is thrown.
public async Task<HealthCheckResult> Execute()
{
if (_configuration.Nodes?.Length == 0)
{
await Task.Delay(1);
return new HealthCheckResult("Connection Failed - Missing elasticsearch connection string")
{
ChildResults = new List<HealthCheckResult>() {new HealthCheckResult()}
};
}
var node = new Uri(_configuration.Nodes.First());
try
{
var connectionPool = new SniffingConnectionPool(new[] {node});
var settings = new ConnectionConfiguration(connectionPool);
var client = new ElasticLowLevelClient(settings);
client.IndicesExists<string>("applications");
}
catch (Exception exception)
{
return new HealthCheckResult(exception.Message)
{
ChildResults = new List<HealthCheckResult>() { new HealthCheckResult() }
};
}
return new HealthCheckResult("Connection Passed")
{
ChildResults = new List<HealthCheckResult>() { new HealthCheckResult() }
};
}
When I execute method above, exception is thrown and I get this message:
Failed sniffing cluster state.
What can I do to check if the connection to Elasticsearch is established?

The Nest IElasticClient interface provides a Ping method for this purpose

I was having the same problem and I managed to fix this by changing the SniffingConnectionPool to a SingleNodeConnectionPool.

Related

MqttNet version 4.1.3.563 Basic example

Following this example I have now therefore been required to update the MQTT.NET from version 3 (that works thanks the provided help) to version 4.
A very basic set of capabilities would be enough:
Connect to an adress with a timeout
Check if the connection has gone well
Receive messages
check disconnection
that was extremely easy in version 3
MqttClientOptionsBuilder builder = new MqttClientOptionsBuilder()
.WithClientId("IoApp" + HelperN.MQTT.GetClientID(true))
.WithTcpServer("localhost", 1883);
ManagedMqttClientOptions options = new ManagedMqttClientOptionsBuilder()
.WithAutoReconnectDelay(TimeSpan.FromSeconds(60))
.WithClientOptions(builder.Build())
.Build();
mqttClient = new MqttFactory().CreateManagedMqttClient();
mqttClient.ConnectedHandler = new MqttClientConnectedHandlerDelegate(OnConnected);
mqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(OnDisconnected);
mqttClient.ConnectingFailedHandler = new ConnectingFailedHandlerDelegate(OnConnectingFailed);
mqttClient.SubscribeAsync(...);
mqttClient.SubscribeAsync(...);
mqttClient.StartAsync(options).GetAwaiter().GetResult();
mqttClient.UseApplicationMessageReceivedHandler(args => { OnMessageReceived(args); });
but when it comes to version 4 if I have to relay on those examples I have problems.
Let's start from the connection
public static async Task Connect_Client_Timeout()
{
/*
* This sample creates a simple MQTT client and connects to an invalid broker using a timeout.
*
* This is a modified version of the sample _Connect_Client_! See other sample for more details.
*/
var mqttFactory = new MqttFactory();
strError = String.Empty;
using (var mqttClient = mqttFactory.CreateMqttClient())
{
var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("aaaa127.0.0.1",1883).Build();
try
{
using (var timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
{
await mqttClient.ConnectAsync(mqttClientOptions, timeoutToken.Token);
}
}
catch (OperationCanceledException exc)
{
strError = "Connect_Client_Timeout exc:" + exc.Message;
}
}
}
And I call this task from the main awaiting the result.
var connectTask = Connect_Client_Timeout();
connectTask.Wait();<-----never ends
Since I put a wrong address "aaaa127.0.0.1" I expect a failure after 5 seconds. But the connectTask.Wait never end. But even if I put the right address "127.0.0.1" it never exits.
So perhaps the error stands in the connectTask.Wait();.
Thanks
The solution is here
In short you have to do this:
static async Task Connect()
{
IManagedMqttClient _mqttClient = new MqttFactory().CreateManagedMqttClient();
// Create client options object
MqttClientOptionsBuilder builder = new MqttClientOptionsBuilder()
.WithClientId("behroozbc")
.WithTcpServer("localhost");
ManagedMqttClientOptions options = new ManagedMqttClientOptionsBuilder()
.WithAutoReconnectDelay(TimeSpan.FromSeconds(60))
.WithClientOptions(builder.Build())
.Build();
// Set up handlers
_mqttClient.ConnectedAsync += _mqttClient_ConnectedAsync;
_mqttClient.DisconnectedAsync += _mqttClient_DisconnectedAsync;
_mqttClient.ConnectingFailedAsync += _mqttClient_ConnectingFailedAsync;
// Connect to the broker
await _mqttClient.StartAsync(options);
// Send a new message to the broker every second
while (true)
{
string json = JsonSerializer.Serialize(new { message = "Hi Mqtt", sent = DateTime.UtcNow });
await _mqttClient.EnqueueAsync("behroozbc.ir/topic/json", json);
await Task.Delay(TimeSpan.FromSeconds(1));
}
Task _mqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
{
Console.WriteLine("Connected");
return Task.CompletedTask;
};
Task _mqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
{
Console.WriteLine("Disconnected");
return Task.CompletedTask;
};
Task _mqttClient_ConnectingFailedAsync(ConnectingFailedEventArgs arg)
{
Console.WriteLine("Connection failed check network or broker!");
return Task.CompletedTask;
}
}
and then just call Connect() and rely on the subscribed examples

How To Delete Multiple Emails From Gmail Using Mailkit?

I am able to delete a single email using Mailkit. But when I am trying to delete multiple emails at a time then I get error "cannot convert from 'System.Collections.Generic.List' to 'MailKit.UniqueId'". Actually, I have all email's UniqueId which I have stored in List.
ex: List uniqueIdList = new List() { 45901, 45902, 45903 };
public async Task BulkDeleteEmailAsync()
{
try
{
List<long> uniqueIdList = new List<long>() { 45901, 45902, 45903 };
SaslMechanismOAuth2 oauth2 = await Authentication();
using (var client = new ImapClient())
{
await client.ConnectAsync("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
await client.AuthenticateAsync(oauth2);
IMailFolder folder = client.GetFolder("INBOX");
folder.Open(FolderAccess.ReadWrite);
if (!folder.IsOpen == true)
throw new Exception($"{folder.FullName} is not open.");
folder.AddFlags(uniqueIdList, MessageFlags.Deleted, false); //here is Error
folder.Expunge(uniqueIdList, CancellationToken.None); //here is Error
folder.Close();
await client.DisconnectAsync(true);
}
}
catch (Exception ex)
{
throw ex;
}
}
From the Documentation here for the AddFlags and for the UniqueId ctor, You may just modifying the init of the list like the following.
For C# 9.0
IList<UniqueId> uniqueIdList = new List<UniqueId>() { new(45901), new(45902), new(45903) };
For older versions
IList<UniqueId> uniqueIdList = new List<UniqueId>() { new UniqueId(45901), new UniqueId(45902), new UniqueId(45903) };
I could find this is getting compiled but could not verify the output though through Fiddle.
Hope this helps!

AWS Lambda will not return query

I have a lambda built with ApiGateway / Serverless.
It will execute a MySQL query. The MySQL Server is up and running and performing other queries with no issues, it seems that this is the only Lambda that returns an empty object.
It accepts a post request with a ID number in the body and then queries the DB and returns the object/data. Like before the server is running correctly. Just this returns and empty object.
I started to think that this maybe completing before the results were returned, I tried running this both sync and aync with the same results.
I am newish to c# so forgive if the code could be more efficient.
No clue as to why this returns a empty object everytime.
namespace Aws.Lambda
{
public class SearchHandler:BaseHandler
{
public async Task<APIGatewayProxyResponse> getId(LambdaRequest request)
{
var error = new Errorhandle();
var connect = new Connection(); //THIS IS THE DATABASE CONNECTION CLASS (WORKS)
var result = new List<ReturnTypes>();
var number = JsonConvert.DeserializeObject<bodyType>(request.body);
bool boolNumber = String.IsNullOrWhiteSpace(number.factura);
try
{
if(boolNumber)
{
return error.errorApiResponse("empty");
}
else
{
await Task.Yield(); // TRYING TO ASYNC / AWAIT THIS,
string x = $"SELECT * FROM Table1 WHERE ID_NUM ='{number}'";
Console.WriteLine(x); //LOGGING THE QUERY FOR ERRORS (NONE FOUND COPY AND PASTED QUERY AND IT WORKED IN WORKBENCH).
var results = connect.getData(x); //QUERY EXECUTE PASS TO FUNCTION MADE IN CLASS
if(!results.Read())
{
return error.errorApiResponse("reader is empty");
}
while (results.Read())
{
resultList.Add(insertData(results));
}
return new APIGatewayProxyResponse
{
StatusCode = 200,
Body = JsonConvert.SerializeObject(resultList),
Headers = headerList = new Dictionary<string, string>
{
{ "Content-Type", "application/json" },
{ "Access-Control-Allow-Origin", "*" },
{"Access-Control-Allow-Methods","OPTIONS,GET"}
};
};
}
} catch (Exception e)
{
return error.errorApiResponse("exception error");
throw e;
}
}
private static ReturnTypes insertData(System.Data.IDataReader results)
{
return new ReturnTypes { Num = results["ID"], Body = results["UUID"];
}
}
}

Flurl PostUrlEncoded does GET instead of POST

I must be missing something very obvious, but I can't tell what. I have a DoLoginAsync like so:
private async Task DoLoginAsync(bool force = false)
{
try
{
if (client.Cookies.ContainsKey("user_credentials") && !force)
{
return;
}
var html = client.Request("login").GetStringAsync().Result;
var doc = new HtmlDocument();
doc.LoadHtml(html);
var csrf_token = doc.DocumentNode.SelectNodes("//meta[#name='csrf-token']").First().GetAttributeValue("content", string.Empty);
var values = new Dictionary<string, string>
{
{ "user_session[email]", user },
{ "user_session[password]", password },
{ "authenticity_token", csrf_token }
};
var result = await client.Request("user_session").PostUrlEncodedAsync(values);
}
catch (Exception e)
{
}
When I run this code in a test with a breakpoint in the catch clause I get an exception
Call failed with status code 404 (Not Found): GET http://www.whatever.com/user_session
WTF? I'm expecting PostUrlEncodedAsync to do a POST, not a GET. Anybody have an idea why this can happen?
The Flurl client is instantiated as client = new FlurlClient(BASE_URL).EnableCookies();
UPDATE
Tried the following test which fails with the same exception
[TestMethod]
public async Task TheTest()
{
var message = "";
try
{
var client = new FlurlClient("http://www.slimmemeterportal.nl/").EnableCookies();
var html = await client.Request("login").GetStringAsync();
var doc = new HtmlDocument();
doc.LoadHtml(html);
var csrf_token = doc.DocumentNode.SelectNodes("//meta[#name='csrf-token']").First().GetAttributeValue("content", string.Empty);
var values = new Dictionary<string, string>
{
{ "user_session[email]", "******" },
{ "user_session[password]", "******" },
{ "commit", "inloggen" }, // Not sure if this is actually needed, but it is in the website's request parameters.
{ "authenticity_token", csrf_token }
};
var result = await client.Request("user_session").PostUrlEncodedAsync(values);
}
catch (FlurlHttpException ex)
{
message = ex.Message;
}
Assert.AreEqual("Call failed with status code 404 (Not Found): POST http://www.slimmemeterportal.nl/user_session", message);
}
Mystery solved: As it turns out after some debugging with Wireshark, the website was returning HTTP status code 301. As explained here the default action is to follow the URI in the response's location header using a GET even if the original request was a POST.

SqlException: do not abort a transaction

I have a code that adds data to two EntityFramework 6 DataContexts, like this:
using(var scope = new TransactionScope())
{
using(var requestsCtx = new RequestsContext())
{
using(var logsCtx = new LogsContext())
{
var req = new Request { Id = 1, Value = 2 };
requestsCtx.Requests.Add(req);
var log = new LogEntry { RequestId = 1, State = "OK" };
logsCtx.Logs.Add(log);
try
{
requestsCtx.SaveChanges();
}
catch(Exception ex)
{
log.State = "Error: " + ex.Message;
}
logsCtx.SaveChanges();
}
}
}
There is an insert trigger in Requests table that rejects some values using RAISEERROR. This situation is normal and should be handled by the try-catch block where the SaveChanges method is invoked. If the second SaveChanges method fails, however, the changes to both DataContexts must be reverted entirely - hence the transaction scope.
Here goes the error: when requestsCtx.SaveChanges() throws a exception, the whole Transaction.Current has its state set to Aborted and the latter logsCtx.SaveChanges() fails with the following:
TransactionException:
The operation is not valid for the state of the transaction.
Why is this happening and how do tell EF that the first exception is not critical?
Really not sure if this will work, but it might be worth trying.
private void SaveChanges()
{
using(var scope = new TransactionScope())
{
var log = CreateRequest();
bool saveLogSuccess = CreateLogEntry(log);
if (saveLogSuccess)
{
scope.Complete();
}
}
}
private LogEntry CreateRequest()
{
var req = new Request { Id = 1, Value = 2 };
var log = new LogEntry { RequestId = 1, State = "OK" };
using(var requestsCtx = new RequestsContext())
{
requestsCtx.Requests.Add(req);
try
{
requestsCtx.SaveChanges();
}
catch(Exception ex)
{
log.State = "Error: " + ex.Message;
}
finally
{
return log;
}
}
}
private bool CreateLogEntry(LogEntry log)
{
using(var logsCtx = new LogsContext())
{
try
{
logsCtx.Logs.Add(log);
logsCtx.SaveChanges();
}
catch (Exception)
{
return false;
}
return true;
}
}
from the documentation on transactionscope: http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28v=vs.110%29.aspx
If no exception occurs within the transaction scope (that is, between
the initialization of the TransactionScope object and the calling of
its Dispose method), then the transaction in which the scope
participates is allowed to proceed. If an exception does occur within
the transaction scope, the transaction in which it participates will
be rolled back.
Basically as soon as an exception is encountered, the transaction is rolled back (as it seems you're aware) - I think this might work but am really not sure and can't test to confirm. It seems like this goes against the intended use of transaction scope, and I'm not familiar enough with exception handling/bubbling, but maybe it will help! :)
I think I finally figured it out. The trick was to use an isolated transaction for the first SaveChanges:
using(var requestsCtx = new RequestsContext())
using(var logsCtx = new LogsContext())
{
var req = new Request { Id = 1, Value = 2 };
requestsCtx.Requests.Add(req);
var log = new LogEntry { RequestId = 1, State = "OK" };
logsCtx.Logs.Add(log);
using(var outerScope = new TransactionScope())
{
using(var innerScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
try
{
requestsCtx.SaveChanges();
innerScope.Complete();
}
catch(Exception ex)
{
log.State = "Error: " + ex.Message;
}
}
logsCtx.SaveChanges();
outerScope.Complete();
}
}
Warning: most of the articles about RequiresNew mode discourage using it due to performance reasons. It works perfectly for my scenario, however if there are any side effects that I'm unaware of, please let me know.

Categories

Resources