Unable to connect to Azure Cosmos Db Account using Microsoft.EntityFrameworkCore.Cosmos - Response status code - azure

The CosmosDb provider is sending this message:
“Response status code does not indicate success: 503 Substatus: 0 Reason: (The request failed because the client was unable to establish connections to 3 endpoints across 1 regions. Please check for client resource starvation issues and verify connectivity between client and server.”
In my tests, it works (.net core 3.1):
Task.Run(async () =>
{
var endpoint = “test”;
var masterKey = “test”;
using (var client = new DocumentClient(new Uri(endpoint), masterKey))
{
//Insert new Document
Console.WriteLine("\r\n>>>>>>>>>>>>>>>> Creating Document <<<<<<<<<<<<<<<<<<<");
dynamic candidato = new
{
Id = 1,
Nome = "Test"
};
var document1 = await client.CreateDocumentAsync(
UriFactory.CreateDocumentCollectionUri("Test", "Test"),
candidato);
Console.ReadKey();
}
}).Wait();
It does not:
Task.Run(async () =>
{
using (var context = new StudentsDbContext())
{
context.Add(new FamilyContainer(2, "Test"));
await context.SaveChangesAsync();
}
}).Wait();
public class FamilyContainer
{
public int Id { get; set; }
public string Nome { get; set; }
public FamilyContainer(int id, string nome)
{
Id = id;
Nome = nome;
}
}
public class StudentsDbContext : DbContext
{
public DbSet<FamilyContainer> FamilyContainer { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseCosmos(
"test",
"test",
"FamilyDatabase",
options =>
{ }
);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<FamilyContainer>(x =>
{
x.ToContainer("FamilyContainer");
});
}
}
Packages
Can anyone help me? Thanks
fail: Microsoft.EntityFrameworkCore.Update[10000]
An exception occurred in the database while saving changes for context type '...'.
Microsoft.EntityFrameworkCore.Storage.RetryLimitExceededException: Maximum number of retries (6) exceeded while executing database operations with 'CosmosExecutionStrategy'. See inner exception for the most recent failure.
---> Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: 503 Substatus: 0 Reason: (Microsoft.Azure.Documents.ServiceUnavailableException: Service is currently unavailable.ActivityId: 07fbf539-0d44-4e5a-89d0-cd46838ee605, {"RequestStartTimeUtc":"2020-02-21T16:34:09.1834993Z","RequestEndTimeUtc":"2020-02-21T16:34:41.3484203Z","RequestLatency":"00:00:32.1649210","IsCpuOverloaded":false,"NumberRegionsAttempted":1,"ResponseStatisticsList":[{"ResponseTime":"2020-02-21T16:34:11.5964152Z","ResourceType":2,"OperationType":0,"StoreResult":"StorePhysicalAddress: rntbd:.../, LSN: -1, GlobalCommittedLsn: -1, PartitionKeyRangeId: , IsValid: True, StatusCode: 410, SubStatusCode: 0, RequestCharge: 0, ItemLSN: -1, SessionToken: , UsingLocalLSN: False, TransportException: A client transport error occurred: Failed to connect to the remote endpoint. (Time: 2020-02-21T16:34:11.5298608Z, activity ID: 07fbf539-0d44-4e5a-89d0-cd46838ee605, error code: ConnectFailed [0x0005], base error: socket error ConnectionRefused [0x0000274D]...
--- End of inner exception stack trace ---

I was facing same issue.
What worked for me is changing ConnectionMode to ConnectionMode.Gateway while initializing CosmosClient like :
var options = new CosmosClientOptions() { ConnectionMode = ConnectionMode.Gateway };
var client = new CosmosClient(endpoint, key, options);
For more details on refer :
https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.cosmosclientoptions?view=azure-dotnet
https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.connectionmode?view=azure-dotnet

TransportException: A client transport error occurred: Failed to connect to the remote endpoint. (Time: 2020-02-21T16:34:11.5298608Z, activity ID: 07fbf539-0d44-4e5a-89d0-cd46838ee605, error code: ConnectFailed [0x0005], base error: socket error ConnectionRefused
This means that the Connection was refused.
Either your Cosmos DB account has Firewall/VPN enabled and the application is not able to establish a connection due not not being in a whitelisted IP/Network : Try checking your account configuration.
The environment you are executing the code is restricting connections (some corporate Firewall or network might be blocking port ranges): Try running the app in a different network, or use GatewayMode. If that works, then this is related to the network.
The machine might be running low on sockets or high on CPU.

My RCA for this is: Cosmos Partitions where served by individual processes on CosmosDB, each partition serving process has it's own TCP port. When client connects to 443 (Using TCP Direct Mode), CosmosDB Proxy sends partition ports back to client so that client can talk to server-partitions in parallel. Partition ports are random (11000 upwards afaik). Normal company firewall would allow outbound 443 (connection to cosmos works) but blocks the outbound random ports. So at the end, access fails.
Workarounds:
Open firewall
Use Gateway Mode. This uses https/443 only by forwarding internally instead of redirecting to other ports.

It is because Entity framework has a default connection mode of Direct. It worked for me after overriding it to Gateway.
{
optionsBuilder.UseCosmos(
"test",
"test",
"FamilyDatabase",
options =>
{ options.ConnectionMode(ConnectionMode.Gateway); }
);
}

I just want to add this because it wasted a lot of my time. The following code would instantly die with an error message that led me to this S.O. post:
var container = _client.Client.GetContainer(_databaseName, containername);
var result = await container.CreateItemAsync(dataitem, pk);
I disbelieved the error message because everything else has worked, upsert, read, etc. After messing with it for a while, I noticed the documentation shows a template type for CreateItemAsync.
var container = _client.Client.GetContainer(_databaseName, containername);
var result = await container.CreateItemAsync<T>(dataitem, pk);
Changing the code to that fixed it (inside of a templated function).
I wanted to add: if I had been catching exceptions, I would have gotten to the meat of the problem much sooner. The library I am working with is not meant to catch exceptions, they are handled by the layer above it.

Related

CosmosDB Container not getting created

CreateContainerIfNotExistsAsync is throwing an exception with status code "Bad Request" if the container does not exist in the db. If the container exists in the db, then no exception is thrown. Can anyone help me why this is happening.
(Hid the url and key for online posting)
using Microsoft.Azure.Cosmos;
using Microsoft.Azure.Cosmos.Linq;
using System.Threading.Tasks;
namespace CosmosDB // Note: actual namespace depends on the project name.
{
class Program
{
public static async Task Main(string[] args)
{
var cosmosUrl = "###########################";
var cosmoskey = "###########################";
var databaseName = "TestDB";
// var containerId = "ToDo";
CosmosClient client = new CosmosClient(cosmosUrl, cosmoskey);
Database database = await client.CreateDatabaseIfNotExistsAsync(databaseName);
Container container = await database.CreateContainerIfNotExistsAsync(
id: "ToDoList",
partitionKeyPath: "/category",
throughput: 100
);
}
}
}
The command fails because your input is invalid. The throughput must be a value between 400 and 10,000 RU/s (for a normal database or container) and since you are using 100 it will throw the exception.
The error won't occur if your container already exists, because it will not check (server-side) or perform an update on the throughput.
Edit:
Link to Microsoft documentation regarding service limits.
Link to Microsoft REST API (used by the SDK).

detect connectivity issue or login failure of ImapMailReceiver

Using Spring integration with Spring mail to connect to IMAP inbox and read emails, I need to detect login failure and network connectivity issues, i cannot find any methods that would let me pull connection status, even errorChannel is not getting any messages nor the logs shows any network connectivity problems
#Bean(name = "getImapMailReceiver")
#Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
ImapMailReceiver getImapMailReceiver(Properties imapConnectionProperties) {
ImapMailReceiver obj = new ImapMailReceiver(imapConnectionProperties.getProperty(IMAP_MAIL_URL_KEY));
obj.setMaxFetchSize(Integer.parseInt(imapConnectionProperties.getProperty(IMAP_MAX_FETCH_SIZE_KEY)));
obj.setJavaMailProperties(imapConnectionProperties);
obj.setShouldDeleteMessages(false);
obj.setAutoCloseFolder(false);
obj.setShouldMarkMessagesAsRead(true);
obj.setSimpleContent(false);
obj.setCancelIdleInterval(10000);
obj.setJavaMailAuthenticator(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(imapConnectionProperties.getProperty("mail.imap.user"),
imapConnectionProperties.getProperty("testpassword"));
}
});
return obj;
}
To catch exceptions from such an ImapIdleChannelAdapter async component, you need to add a even listener for the ImapIdleExceptionEvent.
See more info in docs: https://docs.spring.io/spring-integration/docs/current/reference/html/mail.html#imap-idle-and-lost-connections

Azure Cosmos DB client throws "HttpRequestException: attempt was made to access a socket in a way forbidden by its access permissions" underneath

I use CosmosClient from SDK Microsoft.Azure.Cosmos 3.28.0 in ASP.NET Core 3.1 in Azure Durable Function. This client is getting and sending data from/to my cosmos instance (Core (SQL)) and it works fine but I see that it constantly throws exception in following http request for metadata
GET 169.254.169.254/metadata/instance
System.Net.Http.HttpRequestException: An attempt was made to access a socket in a way forbidden by its access permissions.
I use following configuration:
private static void RegisterCosmosDbClient(ContainerBuilder builder)
{
builder.Register(c => new SocketsHttpHandler()
{
PooledConnectionLifetime = TimeSpan.FromMinutes(10), // Customize this value based on desired DNS refresh timer
MaxConnectionsPerServer = 20, // Customize the maximum number of allowed connections
}).As<SocketsHttpHandler>().SingleInstance();
builder.Register(
x =>
{
var cosmosDbOptions = x.Resolve<CosmosDbOptions>();
var socketsHttpHandler = x.Resolve<SocketsHttpHandler>();
return new CosmosClient(cosmosDbOptions.ConnectionString, new CosmosClientOptions()
{
ConnectionMode = ConnectionMode.Direct,
PortReuseMode = PortReuseMode.PrivatePortPool,
IdleTcpConnectionTimeout = new TimeSpan(0, 23, 59, 59),
SerializerOptions = new CosmosSerializationOptions()
{
PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
},
HttpClientFactory = () => new HttpClient(socketsHttpHandler, disposeHandler: false)
});
})
.AsSelf()
.SingleInstance();
}
I also tried approach with passing IHttpClientFactory from this blog but it didn't help.
It looks like there are no new sockets available in your environment therefore you are getting the socket forbidden error. Please review how to manage connection for Azure Cosmos DB clients and you should use a singleton Azure Cosmos DB client for the lifetime of your application to resolve the issue. In case if you still facing the issue leveraging the singleton object then please let me know so we can further review it.
That particular IP and path is for https://learn.microsoft.com/azure/virtual-machines/windows/instance-metadata-service?tabs=windows
The SDK is attempting to detect the Azure information. It could mean for Durable Functions, this information and endpoint is not available.
This does not affect SDK operations and should not block you from performing other actions on the CosmosClient instance.

How to update Blazor (hosted) upon socket receive event

Hello i have a blazor page in which i want to display a variable.
This variable gets updated from another thread (Task- which receives data over a websocket) and i want to display it in a thread-safe manner:
Blazor Page
#page "/new"
#inherits NewBase
<button onclick="#(async()=>await OnRunPressed())" class="control-button">Run</button>
NewValue :#socketString
public class NewBase:BlazorComponent
{
[Inject] protected BenchService service { get; set; }
protected CancellationTokenSource src = new CancellationTokenSource();
protected string socketString;
protected async Task OnRunPressed()
{
Task updateTask= Task.Run(async () =>
{
var buffer =new byte[1024];
ClientWebSocket socket = new ClientWebSocket();
await socket.ConnectAsync(new Uri("ws://localhost:8500/monitor"), CancellationToken.None);
while (true)
{
await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
this.socketString = Encoding.UTF8.GetString(buffer);
this.StateHasChanged();
}
},src.Token);
await this.service.HitServerAsync(); //does some stuff while the above task works
src.Cancel();
}
}
Update
Thanks to #Dani now i finally at least get an error :
blazor.server.js:16 POST http://localhost:8500/_blazor/negotiate 500 (Internal Server Error)
Error: Failed to start the connection: Error: Internal Server Error
You may be lacking StateHasChanged(); at the end of the OnRunPressed method
I guess this is a server-side Blazor, right ?
If not, then you should know that Mono on WASM is currently single-threaded...
They are no problem about to call StateHasChanged(); after receive data via websocket. All should to run. I have tested it (as server side) and it runs without issues:
https://github.com/ctrl-alt-d/blazorTestingWebSocketsServerSide/tree/master
Also, I have tested it as client side wasm, and they are several issues:
You are using ArrayPool that is a non netstandard2.0 class.
WebSocket is not able to connect from wasm.

Azure + SignalR - Secure hubs to different connection types

I have two hubs in a web role,
1) external facing hub meant to be consumed over https external endpoint for website users.
2) intended to be connected to over http on an internal endpoint by worker roles.
I would like the ability to secure access to the hubs somehow.
Is there anyway I can check to see what connection type the connecting user/worker role is using and accept/deny based on this?
Another method I thought of was perhaps using certificate authentication on the internal hubs but i'd rather not have to for speed etc.
GlobalHost.DependencyResolver.UseServiceBus(connectionString, "web");
// Web external connection
app.MapSignalR("/signalr", new HubConfiguration()
{ EnableJavaScriptProxies = true, EnableDetailedErrors = false });
// Worker internal connection
app.MapSignalR("/signalr-internal", new HubConfiguration()
{ EnableJavaScriptProxies = false, EnableDetailedErrors = true});
EDIT: I've included my own answer
A simple solution you can use roles of client to distinguish between to connections
object GetAuthInfo()
{
var user = Context.User;
return new
{
IsAuthenticated = user.Identity.IsAuthenticated,
IsAdmin = user.IsInRole("Admin"),
UserName = user.Identity.Name
};
}
also other options are fully described here
I ended up probing the request environment variables and checking the servers localPort and request scheme in a custom AuthorizeAttribute. The only downside to this at the moment is that the javascript proxies will still generate the restricted hub info. But i'm working on that :).
I'll leave the question open for a bit to see if anyone can extend on this.
public class SignalrAuthorizeAttribute : Microsoft.AspNet.SignalR.AuthorizeAttribute, Microsoft.AspNet.SignalR.IDependencyResolver
{
public override bool AuthorizeHubConnection(Microsoft.AspNet.SignalR.Hubs.HubDescriptor hubDescriptor, Microsoft.AspNet.SignalR.IRequest request)
{
bool isHttps = request.Environment["owin.RequestScheme"].ToString().Equals("https", StringComparison.OrdinalIgnoreCase) ? true : false;
bool internalPort = request.Environment["server.LocalPort"].ToString().Equals("2000") ? true : false;
switch(hubDescriptor.Name)
{
// External Hubs
case "masterHub":
case "childHub":
if (isHttps && !internalPort) return base.AuthorizeHubConnection(hubDescriptor, request);
break;
// Internal hubs
case "workerInHub":
case "workerOutHub":
if (!isHttps && internalPort) return base.AuthorizeHubConnection(hubDescriptor, request);
break;
default:
break;
}
return false;
}
}

Resources