User already has more than 'max_user_connections' active connections HANGFIRE - c#

I understand
User already has more than 'max_user_connections' active connections
has already many answers. But this is in regard to Hangfire.
I am using Hangfire for background processing.
It worked fine for the first time and only when I started my application. But now its not. SO now when I am trying to open the database to see what's happening it gives me this error.
My idea is that it cannot execute any more items in the queue because it cannot connect to the database.
Also, I cannot open the Hangfire dashboard. It gives 404 error.
I have created the OWIN startup.cs as
using Hangfire;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(MyApp.Startup))]
namespace MyApp
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseHangfireDashboard();
}
}
}
Also, I have put the code as required in Application_Start in Global.asax.cs as:
var options = new Hangfire.MySql.MySqlStorageOptions
{
QueuePollInterval = TimeSpan.FromSeconds(15), // Default value
PrepareSchemaIfNecessary = false
};
Hangfire.MySql.MySqlStorage storage = new Hangfire.MySql.MySqlStorage("hangfire2", options);
GlobalConfiguration.Configuration.UseStorage(storage);
_backgroundJobServer = new BackgroundJobServer();
Is there any way I can avoid max_user_connection error ? Or actually, run the background call.
Here it is how I am calling it:
BackgroundJob.Enqueue(() => MyMethod());
UPDATE:
After timeout, I saw the database and found that Second operation was not inserted into database, however, the third one was inserted but gives the state of the job as this:
Retry attempt 1 of 10: Exception has been thrown by the target of an inv...

Related

Azure Function c# - Retrieve list of subscription's WebApp

We want to create an azure function in c# that retrieve the list of azure web app contained in the subscription (basically we want to call dynamically, for each webapp, the same API endpoint changing the subdomain of the api).
It's possible with c# retrieve the list of the web app contained in the same azure function subscriptions?
Usually we connect to the master database, we query the sys.databases to collect the dbname and understand the webapp names. But we are searching for a smartest way.
If you're in C# land, I'd look at using the ArmClient class to retrieve what you're looking for.
Install these (I've got a few others installed but start with that and see how you go, there may be a couple of others needed) Nuget packages ...
Azure.Identity;
Azure.ResourceManager;
Azure.ResourceManager.AppService
... and from there, using the DefaultCredential approach (if you've never used it, read up on it here -> https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/README.md) you can query your subscriptions webApps ...
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.AppService;
using System;
using System.Threading.Tasks;
namespace AzureManagement
{
internal class Program
{
static void Main(string[] args)
{
GetAzureResources().Wait();
}
static async Task GetAzureResources()
{
var credential = new DefaultAzureCredential();
var armClient = new ArmClient(credential);
var subscription = await armClient.GetDefaultSubscriptionAsync();
var webSitesEnumerator = subscription.GetWebSitesAsync().GetAsyncEnumerator();
try
{
while (await webSitesEnumerator.MoveNextAsync())
{
var webSite = webSitesEnumerator.Current;
Console.WriteLine($"Web App Name ........ {webSite.Data.Name}");
Console.WriteLine($"Default Host Name ... {webSite.Data.DefaultHostName}\n");
}
}
finally
{
await webSitesEnumerator.DisposeAsync();
}
Console.ReadLine();
}
}
}
The above is obviously not a function app but the core code will still work for you and can be ported as need be.
Note: I could be telling you how to suck eggs, but, once deployed to Azure, you'll need to do the necessary work to ensure that the function app has the required access to retrieve all of the resource information you're looking for.
If you're unfamiliar with that, read up on the managed identity concept. It's very easy to setup -> https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity
Yes, one easy way is to use HttpClient and send a request to Azure Rest API:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Web/sites?api-version=2022-03-01
https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/list
PS: you first need to acquire an authentication token.
https://www.youtube.com/watch?v=6b1J03fDnOg&t=329s

Execution of SetCommandTimeout not working with EF Core 5 for PostgreSQL

I have a problem when I SetCommandTimeout is like the method is not working properly.
I Use PostgreSQL as database, and for the EntityFramework Core I'm using Npgsql.EntityFrameworkCore.PostgreSQL with Version 5.0.5.1
In the code I Set Timeout for 1s like this context.Database.SetCommandTimeout(1); and I set a Stopwatch to check how much time it takes, but the ElapsedMiliseconds always return around 15000ms to 16000ms. so the SetCommandTimeout(1) is clearly not working.
I also tried using context.Database.SetCommandTimeout(TimeSpan.FromSeconds(1)); is not working either.
One more thing, I only want to Set Timeout for specific Request. So the other Request will have the default timeout.
Here's my code:
[Route("api/[controller]")]
[ApiController]
public class TestController : Controller
{
private readonly DatabaseContext context;
public TestController(DatabaseContext context)
{
this.context = context;
}
[AllowAnonymous]
[HttpGet]
public async Task<IActionResult> Test()
{
var sw = Stopwatch.StartNew();
try
{
context.Database.SetCommandTimeout(1);
var test = await context.Test.FirstOrDefaultAsync();
return Ok();
}
catch (Exception)
{
return BadRequest();
}
finally
{
sw.Stop();
var elapsed = sw.ElapsedMilliseconds; // always return around 15000ms to 16000ms
}
}
}
here's how I register it in Startup.Cs
services.AddDbContext<DatabaseContext>(options =>
{
options.UseNpgsql(ConnectionString);
});
did I missing something?
Thanks in advance
The command timeout is the time a query / command is allowed to execute on the database server. The timer starts when the database server receives the request. Your end-to-end round trip time may be higher than the command timeout due to network throughput or other constraints - including resource exhaustion on your web server.
Command Timeout: The time to wait (in seconds) while trying to execute a command before terminating the attempt and generating an error.
Source
Googled a little and found issues related to this library.
Based on this forum post, it seems that the issue is coming from the source code and the settings is just being ignored.
Try to set-up command timeout inside the creating of DB context instead right before usage.
Another one is at the github repository.
Solution for this one is to upgrade to latest version of drivers.
Another from github.
The workaround for this is to modify connection string during creation of context:
if (!connectionString.Contains("CommandTimeout"))
{
connectionString += $";CommandTimeout=120";
}
EDIT (after OP mentioned he wants to use it on single request): I would recommend by going the way with creating other database context and modifying its connection string (as above). That way you would be able to execute short/long running commands. However, this brings other issues related to the multiple DB-context and possible mismatch of data. Needs to be handled with caution.

Azure WebJobs QueueTrigger not triggering

I'm trying to find what I'm doing wrong regarding an Azure WebJobs QueueTrigger method that should be triggered from an Azure Storage Queue.
I've read a couple of documents (as in blog posts / msdn articles). But I'm still not clear.
Main question / misunderstood aspect:
What should be the name of the connection string for Azure storage console app App.config or Windows Azure Configuration (portal). So far I have the following name set at both places.
AzureJobsStorage
AzureWebJobsStorage
AzureJobsRuntime
AzureJobsDashboard
AzureJobsData
Here's my WebJobs console app code.
static void Main()
{
JobHost host = new JobHost();
host.RunAndBlock();
}
public static void CreateLeague([QueueTrigger("temp")] string msg)
{
var task = JsonConvert.DeserializeObject<QueueTask>(msg);
if (task.TaskType == QueueTask.TaskTypes.Pdf)
RenderPdf(task.Id);
}
This console app is continuously running on my Azure Website.
I can access its "debug" page where I can toggle output and I see it is started / running.
My code to add queue (from my ASP.NET MVC app):
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueClient.GetQueueReference("temp");
queue.CreateIfNotExists();
Common.QueueTask task = new Common.QueueTask();
task.TaskType = Common.QueueTask.TaskTypes.Pdf;
task.Id = p.Id;
CloudQueueMessage msg = new CloudQueueMessage(JsonConvert.SerializeObject(task) );
queue.AddMessage(msg);
This code is executed, and queue are added to my Storage Account. But they did not get "dequeue" or read from the WebJobs.
Hmm, the WebJobs class had to be public.
using Microsoft.Azure.WebJobs;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Newtonsoft.Json;
using Proceed.Common;
using System;
using System.Configuration;
using System.IO;
public class WebJobsTask {
public static void Main()
{
JobHost host = new JobHost();
host.RunAndBlock();
}
public static void CreateLeague([QueueTrigger("temp")] string msg)
{
var task = JsonConvert.DeserializeObject<QueueTask>(msg);
if (task.TaskType == QueueTask.TaskTypes.Pdf)
RenderPdf(task.Id);
}
}
Also found a quick way to explore my queues: https://azurestorageexplorer.codeplex.com/.
In my case, I had assumed that QueueTrigger was referring to Service Bus Queues instead of Azure Queues, and I actually needed to use ServiceBusTrigger.
You can use the server explorer in VS to explore the content of the Storage queues.
The queue triggers for the WebJobs SDK will exponentially back off if there is no work to do. There might be a delay between the moment a message is put in a queue and the moment when it is picked up. You can configure the maximum back off through the JobHostConfiguration.Queues.MaxPollingInterval property.
For the latest SDK you need two storage connection strings AzureWebJobsStorage and AzureWebJobsDashboard
This is a great place for more resources: https://learn.microsoft.com/en-us/azure/app-service-web/websites-webjobs-resources

How to reconfigure SQLTransport based NServicebus in Asp.net Web API?

I am using NServicebus(version 4.6.3) with SQLTransport in my ASP.net web api project. I have different connectionstrings for the queues for different environments (Dev,QA,etc). My configuration looks like below:
public class BusConfigurator
{
public static IStartableBus Bus { get; private set; }
public static void DisposeBus()
{
if (Bus == null)
return;
Bus.Shutdown();
Bus.Dispose();
Bus = null;
}
public static void InitializeServiceBus(string connectionString)
{
var configure = Configure.With()
.DefineEndpointName("MyEndPoint")
.Log4Net(new DebugAppender { Threshold = Level.Warn })
.UseTransport<SqlServer>(connectionString)
.PurgeOnStartup(false)
.SetDefaultTransactionLevel()
.UnicastBus(); // Error is thrown here on second call
configure.MyCustomSQLServerPersistence();
Bus = configure.CreateBus();
}
public static void StartBus()
{
Bus.Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
}
}
I have a dropdown in the app so that the user can select the environment. Based on the selection, I want to reconfigure the bus. So, I call DisposeBus then pass the connection string to the IntializeServiceBus method followed by the startBus. It works first time but throws error below when it gets called again with different connectionstring:
Unable to set the value for key: NServiceBus.Transport.ConnectionString. The settings has been locked for modifications. Please move any configuration code earlier in the configuration pipeline
Source=NServiceBus.Core
Line=0
BareMessage=Unable to set the value for key: NServiceBus.Transport.ConnectionString. The settings has been locked for modifications. Please move any configuration code earlier in the configuration pipeline
Is NServicebus intended to be used/configured this way? (I am guessing probably not) If not then is there a workaround/different approach for this?
In V4 or below, there is no way to do it by normal human means. There is only one Bus per AppDomain. All of the configuration API is static, so if you try, you get exactly the problems you ran into.
By "human means", I mean that it might be possible to do something crazy with spinning up a new AppDomain within your process, setting up a Bus within that, and then tearing it down when you're finished. It might be possible. I haven't tried it. I wouldn't recommend it.
In V5, the configuration API is completely redesigned, is not static, and so this is possible:
var cfg = new BusConfiguration();
// Set up all the settings with the new V5 Configuration API
using (var justOneBus = NServiceBus.Bus.Create(cfg).Start())
{
// Use justOneBus, then it gets disposed when done.
}
That's right. It's disposable. Then you can do it again. In your case you wouldn't want to put it in a using block - you would want to set it up somewhere, and when the dropdown gets switched, call Dispose on the current instance and rebuild it with the new parameters.
Keep in mind, however, that the Bus is still pretty expensive to create. It's definitely still something you want to treat as an application-wide singleton (or singleton-like) instance. You definitely wouldn't want to spin up a separate one per web request.

ServiceStack RedisMessageQueueClient strange behavior

My infrastructure:
Main - ServiceStack self hosted console app. 'Main' sends messages to MQ.
Background - ServiceStack self hosted console app. 'Background' receives messages from MQ.
Locally installed Redis
In 'Main' AppHost I configure Redis manager:
container.Register<IRedisClientsManager>(
new PooledRedisClientManager("localhost:6379"));
Then I run this code somewhere in service:
using (var client = new RedisMessageQueueClient(TryResolve<IRedisClientsManager>()))
{
client.Publish(new TestMessage { Value = "From ping" });
}
Everything works great and I can get message in my 'Background'. But problem comes when I wrap this code in class:
public class MessageQueuePublisher : IMessageQueuePublisher
{
public void Publish(object message)
{
using (var client = new RedisMessageQueueClient(
EndpointHost.AppHost.TryResolve<IRedisClientsManager>()))
{
client.Publish(message);
}
}
}
When I call MessageQueuePublisher.Publish method from the exactly same place where previous code was executed, it seems like it works correctly (no exceptions are thrown), but my message doesn't reach 'Background'.
Is this OK?
I found a solution. On my 'Background' I expect message with type TestMessage
mqService.RegisterHandler<TestMessage>(ServiceController.ExecuteMessage);
But when using MessageQueuePublisher.Publish message was of type object and went to the object queue and wasn't handled.
So to solve this problem Publish method should be generic:
public void Publish<T>(T message)
It doesn't change how method is called but code is not so good because if you look at it, it's not clear why generic is used. But at least it works.

Categories