I assumed that we should use basicredisclientmanager or pooledredisclientmanager?
I tried this
private void dddddd()
{
for(int i=0;i<=1000;i++)
{
var client = new BasicRedisClientManager(new string[] { "host1", "host2", "host3" }).GetClient();
//do something with client
}
}
This loop runs fine for the first 100 plus but after that, I always got an error "Unknown Command Role"?? What is that and how to fix it? I need help!
I also tried to make a new class called MyRedisMgr and created a static property to create some sort of singleton but it didn't work either.
public BasicRedisClientManager MyMgr = new BasicRedisClientManager(new string[] { "host1", "host2", "host3" });
And then I use it like
for(int i=0;i<=1000;i++)
{
var client = MyRedisMgr.MyMgr.GetClient();
//do something with client
}
Please read the documentation on the proper usage of Redis Client Manager which should only be used as a singleton.
The BasicRedisClientManager doesn't have any connection pooling so every time you call GetClient() you're opening a new TCP connection with the redis-server. Unless you understand the implications you should be using one of the Pooled Redis Client Managers, e.g: RedisManagerPool.
You also need to always dispose the client after its used so that it can either be re-used or the TCP connection disposed of properly.
So your code sample should look like:
//Always use the same singleton instance of a Client Manager
var redisManager = new RedisManagerPool(masterHost);
for(int i=0;i<=1000;i++)
{
using (var redis = redisManager.GetClient())
{
//do something with client
}
}
The "Unknown Command Role" error is due to using an old version of Redis Server. The ROLE command was added in redis 2.8.12 but this API should only be used if your using redis-server v2.8.12+, so you shouldn't be getting this error by default. You can avoid this error by upgrading to either the stable v3.0 or old 2.8 versions of redis-server which has this command.
If you want to continue using an older version, use the INFO command to check what version you're running then tell ServiceStack.Redis what the version is with:
RedisConfig.AssumeServerVersion = 2600; //e.g. v2.6
RedisConfig.AssumeServerVersion = 2612; //e.g. v2.6.12
Related
This YouTube video #27:20 talks about populating the cache with routing info to avoid latency during a cold start.
You can either try to get a document you know doesn't exist, or you can use CosmosClient.CreateAndInitializeAsync().
I already have this code set up:
private async Task<Container> CreateContainerAsync(string endpoint, string authKey)
{
var cosmosClientBuilder = new CosmosClientBuilder(
accountEndpoint: endpoint,
authKeyOrResourceToken: authKey)
.WithConnectionModeDirect(portReuseMode: PortReuseMode.PrivatePortPool, idleTcpConnectionTimeout: TimeSpan.FromHours(1))
.WithApplicationName(UserAgentSuffix)
.WithConsistencyLevel(ConsistencyLevel.Session)
.WithApplicationRegion(Regions.AustraliaEast)
.WithRequestTimeout(TimeSpan.FromSeconds(DatabaseRequestTimeoutInSeconds))
.WithThrottlingRetryOptions(TimeSpan.FromSeconds(DatabaseMaxRetryWaitTimeInSeconds), DatabaseMaxRetryAttemptsOnThrottledRequests);
var client = cosmosClientBuilder.Build();
var databaseResponse = await CreateDatabaseIfNotExistsAsync(client).ConfigureAwait(false);
var containerResponse = await CreateContainerIfNotExistsAsync(databaseResponse.Database).ConfigureAwait(false);
return containerResponse;
}
Is there any way to incorporate CosmosClient.CreateAndInitializeAsync() with it to populate the cache?
If not, is it ok to do this to populate the cache?
public class CosmosClientWrapper
{
public CosmosClientWrapper(IKeyVaultFacade keyVaultFacade)
{
var container = CreateContainerAsync(endpoint, authenticationKey).GetAwaiter().GetResult();
// Get a document that doesn't exist to populate the routing info:
container.ReadItemAsync<object>(Guid.NewGuid().ToString(), PartitionKey.None).GetAwaiter().GetResult();
}
}
The point of CreateAndInitialize or BuildAndInitialize is to pre-establish the connections required to perform Data Plane operations to the desired containers (reference https://learn.microsoft.com/azure/cosmos-db/nosql/sdk-connection-modes#routing).
If the containers do not exist, then it makes no sense to use CreateAndInitialize or BuildAndInitialize because there are no connections that can be pre-established/warmed up, because there are no target backend endpoints to connect to. That is why the container/database information is required, because the only benefit is warming up the connections to the backend machines that support that/those container/s.
Please see CosmosClientBuilder.BuildAndInitializeAsync which creates the cosmos client and initialize the provided containers. I believe this is what you are looking for.
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.
I upgraded to version 5.1.1 of ServiceStack OrmLite (via MyGet), and when I try to open a connection to the db, I suddenly get this error:
MySql.Data.MySqlClient.MySqlException: 'The host 127.0.0.1 does not support SSL connections.'
Before the upgrade I was running v 5.1.0, and I got no such error.
I initialize OrmLite as follows:
private void InitOrmLite()
{
JsConfig.IncludeTypeInfo = true;
OrmLiteConfig.ThrowOnError = JsConfig.ThrowOnError = true;
//OrmLiteConfig.BeforeExecFilter = dbCmd => Console.WriteLine(dbCmd.GetDebugString());
_dbFactory = new OrmLiteConnectionFactory($"Uid={dbUsername};Password={dbPassword};Server={dbAddress};Port={dbPort};Database={dbDatabase}", MySqlDialect.Provider);
SetTableMeta();
}
and usage is
using (var _db = dbFactory.Open())
{
// AlterTable will create if not exist, otherwise add columns that was added to the PCO
_db.AlterTable<Customer>(MySqlDialect.Provider);
}
And here it is:
There is a workaround, that I am posting as an answer, but I'd like mythz input on this =)
The workaround that I found, is to add the following to the connection string:
SslMode=None
so, the connectionstring would be:
$"Uid={dbUsername};Password={dbPassword};Server={dbAddress};Port={dbPort};Database={dbDatabase};SslMode=None",
MySqlDialect.Provider
When doing so, the exception is gone.
I'm using a Node.JS backend on Azure with Easy Tables. The table contains the required columns to support offline syncing.
While testing the sync process I noticed that conflicts keep coming back even though I'm resolving them.
My test:
Pull table content from Azure to iOS and Android device
Change a record on iOS but don't sync back to Azure
Change the same record on Android and sync
Now sync iOS
As expected, the conflict is detected correctly and I catch a MobileServicePushFailedException. I am then resolving the error by replacing the local item with the server item:
localItem.AzureVersion = serverItem.AzureVersion;
await result.UpdateOperationAsync(JObject.FromObject (localItem));
However, the next time I sync, the same item fails again with the same error.
The AzureVersion property is declared like this:
[Version]
public string AzureVersion { get; set; }
What exactly is result.UpdateOperationAsync() doing? Does it update my local database? Do I have to do it manually?
And also: am I supposed to trigger an explicit PushAsync() afterwards?
EDIT:
I changed the property from AzureVersion to Version and it works. I noticed that the serverItem's AzureVersion property was NULL even though the JSON contained it. Bug in Json.Net or in the Azure Mobile Client?
You should be using something like the following:
public async Task SyncAsync()
{
ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
try
{
await this.client.SyncContext.PushAsync();
await this.todoTable.PullAsync(
//The first parameter is a query name that is used internally by the client SDK to implement incremental sync.
//Use a different query name for each unique query in your program
"allTodoItems",
this.todoTable.CreateQuery());
}
catch (MobileServicePushFailedException exc)
{
if (exc.PushResult != null)
{
syncErrors = exc.PushResult.Errors;
}
}
// Simple error/conflict handling. A real application would handle the various errors like network conditions,
// server conflicts and others via the IMobileServiceSyncHandler.
if (syncErrors != null)
{
foreach (var error in syncErrors)
{
if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
{
//Update failed, reverting to server's copy.
await error.CancelAndUpdateItemAsync(error.Result);
}
else
{
// Discard local change.
await error.CancelAndDiscardItemAsync();
}
Debug.WriteLine(#"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]);
}
}
}
Note the CancelAndUpdateItemAsync(), which updates the item to the server copy or CancelAndDiscardItemAsync(), which accepts the local item. These are the important things for you.
This code came from the official HOWTO docs here: https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-dotnet-how-to-use-client-library/##offlinesync
Whatever I tried I cannot set an extension property on a User object, here is a reproducible piece of code:
public async Task CleanTest(string extName)
{
ExtensionProperty ep = new ExtensionProperty
{
Name = extName,
DataType = "String",
TargetObjects = { "User" }
};
App app = (App)(await _client.Applications.Where(a => a.AppId == _managementAppClientId).ExecuteSingleAsync());
app.ExtensionProperties.Add(ep);
await app.UpdateAsync();
GraphUser user = (GraphUser)(await _client.Users.Where(u => u.UserPrincipalName.Equals("email")).ExecuteSingleAsync());
string propName = FormatExtensionPropertyName(extName); //formats properly as extesion_xxx_name
user.SetExtendedProperty(propName, "testvalue");
//user.SetExtendedProperty(extName, "testvalue");
await user.UpdateAsync(); // fails here
}
user.UpdateAsync() according to Fiddler doesn't even go out and application fails with an exception:
"The property 'extension_e206e28ff36244b19bc56c01160b9cf0_UserEEEqdbtgd3ixx2' does not exist on type 'Microsoft.Azure.ActiveDirectory.GraphClient.Internal.User'. Make sure to only use property names that are defined by the type."
This issue is also being tracked here:
https://github.com/Azure-Samples/active-directory-dotnet-graphapi-console/issues/28
I've got an alternative workaround for this bug, for those that want to use the version 5.7 OData libraries rather than redirecting to the v5.6.4 versions.
Add a request pipeline configuration handler.
// initialize in the usual way
ActiveDirectoryClient activeDirectoryClient =
AuthenticationHelper.GetActiveDirectoryClientAsApplication();
// after initialization add a handler to the request pipline configuration.
activeDirectoryClient.Context
.Configurations.RequestPipeline
.OnMessageWriterSettingsCreated(UndeclaredPropertyHandler);
In the handler, change the ODataUndeclaredPropertyBehaviorKinds value on the writer settings to SupportUndeclaredValueProperty.
private static void UndeclaredPropertyHandler(MessageWriterSettingsArgs args)
{
var field = args.Settings.GetType().GetField("settings",
BindingFlags.NonPublic | BindingFlags.Instance);
var settingsObject = field?.GetValue(args.Settings);
var settings = settingsObject as ODataMessageWriterSettings;
if (settings != null)
{
settings.UndeclaredPropertyBehaviorKinds =
ODataUndeclaredPropertyBehaviorKinds.SupportUndeclaredValueProperty;
}
}
Just in case you still looking for solution to this problem or someone else is facing the same issue:
I got similar issue and it looks like, at least for me, the problem was in latest version of "Microsoft.Data.Services.Client" package - 5.7.0 (or in one of it dependencies). When I downgraded to previous version - 5.6.4 it worked as a charm.
I had same symptoms - updating of extended property was failing even w/o any request is made (also used Fiddler)
Hope it helps!
Artem Liman