Start Service Bus Client from BackgroundService - .net-core

I have a ServiceBusClient class that creates a QueueClient which is used to listen for messages on a bus. I have looked at the following articles to set this up:
Background tasks (Microsoft)
Hosted services (Microsoft)
Async and Await
My ServiceBusClient class that handles the QueueClient looks like this:
public class ServiceBusClient : IServiceBusClient
{
public ServiceBusClient(IEventService eventService, ServiceBusClientOptions options)
{
...
queueClient = new QueueClient(options.ConnectionString, options.QueueName);
}
public void Run()
{
RegisterOnMessageHandler();
}
private void RegisterOnMessageHandler()
{
...
queueClient.RegisterMessageHandler(ProcessMessagesAsync, messageHandlerOptions);
}
private async Task ProcessMessagesAsync(Message message, CancellationToken token)
{
var eventMessage = EventMessage.FromMessage(message);
await eventService.Write(eventMessage);
if (!token.IsCancellationRequested)
{
await queueClient.CompleteAsync(message.SystemProperties.LockToken);
}
}
private Task ExceptionReceivedHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs)
{
// log errors
...
return Task.CompletedTask;
}
}
I was hoping to launch from an IHostedService or even by extending the BackgroundService. In the examples I find, work is constantly being executed in a while loop which does not fit my scenario since I am only trying to run a single command.
So I created a super simple implementation like this:
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
serviceBusClient.Run();
while (!cancellationToken.IsCancellationRequested)
{
// empty loop to keep running for lifetime of pod
}
}
If removing the async I obviously need to return something. I tried Task.CompletedTask but that required me to change the return type to Task<Task>.
If I have the async in place, I will need to await something, but I am not sure what.
This does not feel right. I would assume I would need to change something in the ServiceBusClient, but I am unsure what, since the ProcessMessagesAsync is async and does the heavy lifting in the background from my understanding.
All I want is for my web app to start listening for messages until it dies. How can I do that?

I gave up on using BackgroundService and implemented IHostedService instead.
public class MessageListenerService : IHostedService
{
private readonly IServiceBusClient client;
private readonly ITelemetryClient applicationInsights;
public MessageListenerService(IServiceProvider serviceProvider)
{
client = serviceProvider.GetService<IServiceBusClient>();
applicationInsights = serviceProvider.GetService<ITelemetryClient>();
}
public Task StartAsync(CancellationToken cancellationToken)
{
applicationInsights.TrackTrace(new TraceTelemetry("MessageListenerService is starting"));
client.Run();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
applicationInsights.TrackTrace(new TraceTelemetry("MessageListenerService is stopping"));
return client.Stop();
}
}
If you find issues with this code please let me know in the comments and I'll update as appropriate.
In the end we created a console app for it anyway.

Related

Unity async/await and IO operations with Firestore (Firebase)

I've developed a Unity App that uses Firebase as a BaaS and Firestore as a Database.
Firebase has a Client SDK to make calls that are usually called from client to server by an URL endpoint.
My concern is how my methods should be implemented to correctly work on client without blocking the user experience, cause if I made a heavy request, my Unity App is blocked, and no interaction is allowed to the user.
This is the code of my client DatabaseManager with the methods to retrieve a User from Firestore:
public class DatabaseManager
{
public DatabaseManager(FirebaseFirestore db)
{
this.db = db;
}
public async Task<User> GetUserByUIDAsync(string uid)
{
string documentID = uid;
return await AsyncGetDocumentFromCollection<User, User_FirestoreData>(COL_ID_USERS, documentID);
}
public async Task<PlainData> AsyncGetDocumentFromCollection<PlainData, FirestoreData>(string collectionID, string documentID) where PlainData : IConvertToFirestore<FirestoreData> where FirestoreData : IConvertToPlainData<PlainData>
{
try
{
DocumentReference docRef = db.Collection(collectionID).Document(documentID);
DocumentSnapshot documentSnapshot = await docRef.GetSnapshotAsync();
if (documentSnapshot.Exists)
{
Debug.Log("Get Document data for document:" + documentSnapshot.Id);
FirestoreData firestoreData = documentSnapshot.ConvertTo<FirestoreData>();
return firestoreData.ToPlainData();
}
else
{
Debug.Log($"Document {documentSnapshot.Id} does not exist!");
}
}
catch (Exception e)
{
Debug.Log(e);
}
return default(PlainData);
}
}
This is a simple call and when it's called from any MonoBehaviouryou couldn't notice the load difference when you call it like:
using UnityEngine.UI;
public class MyMono : MonoBehaviour
{
private void DatabaseManager db;
[SerializedField] private Button button = null;
private void Awake()
{
button.onClick.AddListener(async ()=> await CustomAwakeAsync(db));
}
private async Task CustomAwakeAsync(DatabaseManager db)
{
//if this Async method is heavier, this will block the main UI thread when the button is pressed
await db.GetUserByUIDAsync("xdfipñfajrfiñar");
}
}
But if instead of GetUserByUIDAsync I make a heavy call, or multiple recursive calls my application UI will freeze until it's finished...which is bad.
How should I build my code to avoid these case?
Note:
My easy way to test if it's blocking UI thread is having this class attached to a GameObject with Image component:
using UnityEngine;
public class InfiniteRotate : MonoBehaviour
{
public float speed = 1;
// Update is called once per frame
private void Update()
{
this.gameObject.transform.Rotate(0, 0, 1 * Time.deltaTime * speed);
}
}
If the image stop spinning, means that async/await is blocking the UI thread.
Your code as shown:
private void CustomAwake(DatabaseManager db)
{
await db.GetUserByUIDAsync("xdfipñfajrfiñar");
}
...should be producing the following error:
error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
Even if somehow you managed to silence this error the method signature private void CustomAwake(DatabaseManager db) clearly indicates that this method is synchronous to the caller.
OP:
But if instead of GetUserByUIDAsync I make a heavy call, my application UI will freeze until it's finished...which is bad.
So if you are calling this from the same thread as Update, FixedUpdate etc (which by the looks of it you are) then you are going to block Unity and thus slow down your game.
If you are going to use async/await then you need to do so all the way back to the original caller.
Make it asynchronous
Change the method to:
private async Task<User> CustomAwake(DatabaseManager db) // Note the async Task
{
return await db.GetUserByUIDAsync("xdfipñfajrfiñar");
}
...and ensure that whatever calls it uses await in order to get the User.

Blazor WebAssembly SignalR HubConnection causing javascript error on reload

I have a SignalR HubConnection within my Blazor WebAssembly application and whilst it works most of the time, if I reload the page (via the browser reload) then I often am getting the following error in the console and the connection is not made:
Uncaught Error: The delegate target that is being invoked is no longer available. Please check if it has been prematurely GC'd.
at Object.invoke_delegate (dotnet.5.0.4.js:1)
at WebSocket. (dotnet.5.0.4.js:1)
Here's a rough, simplified view of the code where I create the HubConnection (and dispose it).
#inherits LayoutBase
#attribute [Authorize]
<AuthorizeView>
<Authorized>
//...
</Authorized>
<NotAuthorized>
//...
</NotAuthorized>
</AuthorizeView>
public class LayoutBase : LayoutComponentBase, IAsyncDisposable
{
[Inject] public IAccessTokenProvider AccessTokenProvider { get; set; }
private readonly HubConnection _hubConnection;
protected override async Task OnInitializedAsync()
{
_hubConnection = new HubConnectionBuilder()
.AddNewtonsoftJsonProtocol(c =>
{
//...
})
.WithUrl(notificationHubUrl, option => option.AccessTokenProvider = GetAccessToken)
.WithAutomaticReconnect()
.Build();
_hubConnection.Closed += HubConnectionOnClosed;
_hubConnection.Reconnected += HubConnectionOnReconnected;
_hubConnection.Reconnecting += HubConnectionOnReconnecting;
await _hubConnection.StartAsync()
await base.OnInitializedAsync();
}
private async Task<string> GetAccessToken()
{
var tokenResult = await AccessTokenProvider.RequestAccessToken(...)
// etc...
}
// .. Event Handlers
public ValueTask DisposeAsync()
{
_logger.LogInformation($"Disposing Hub: {_hubConnection.ConnectionId}");
_hubConnection.Closed -= HubConnectionOnClosed;
_hubConnection.Reconnected -= HubConnectionOnReconnected;
_hubConnection.Reconnecting -= HubConnectionOnReconnecting;
return _hubConnection.DisposeAsync();
}
}
Previously I had it as an injected service but I eventually simplified it to this structure but it continues to get this error on reload. It's not every time I reload but most times.
I have tried changing the dispose pattern without success. I can't find any information on the error anywhere else.
Any ideas?
I don't have a definitive answer as to the underlying reason but I suspect that this is a bug somewhere in the SignalR/dotnet framework resulting in the GCing of a delegate because something drops a reference to it.
One way I've managed to provoke this error reasonably consistently is to have a handler returning just a Task, e.g.
_hubConnection.On<TEvent>(eventType.Name, OnEvent);
where OnEvent looks like this:
// THIS IS THE BROKEN SIGNATURE - DO NOT USE
private async Task OnEvent<TEvent>(TEvent e)
{
}
A workaround which appears to have fixed it for me is to make the handler actually return something. This seems to make something deeper in the framework hold a reference for longer so that it doesn't get GC'ed. E.g.
// WORKS ON MY MACHINE - Note the return type of Task<object>
private async Task<object> OnEvent<TEvent>(TEvent e)
{
// ... Do stuff
return null;
}

rewrite an IHostedService to stop after all tasks finished

I have an application that normally should be a simple console application to be programmed as a scheduled task from time to time called by the windows task scheduler.
The program should launch some updates on two databases, one service per one database. Say ContosoDatabase should be updated by the ContosoService.
Finally it was written as an .NET Core app using, and maybe is not the best choice, the IHostedServices as base for the service, like this:
public class ContosoService : IHostedService {
private readonly ILogger<ContosoService> _log;
private readonly IContosoRepository _repository;
private Task executingTask;
public ContosoService(
ILogger<ContosoService> log,
IContosoRepository repository,
string mode) {
_log = log;
_repository = repository;
}
public Task StartAsync(CancellationToken cancellationToken) {
_log.LogInformation(">>> {serviceName} started <<<", nameof(ContosoService));
executingTask = ExcecuteAsync(cancellationToken);
// If the task is completed then return it,
// this should bubble cancellation and failure to the caller
if (executingTask.IsCompleted)
return executingTask;
// Otherwise it's running
// >> don't want it to run!
// >> it should end after all task finished!
return Task.CompletedTask;
}
private async Task<bool> ExcecuteAsync(CancellationToken cancellationToken) {
var myUsers = _repository.GetMyUsers();
if (myUsers == null || myUsers.Count() == 0) {
_log.LogWarning("{serviceName} has any entry to process, will stop", this.GetType().Name);
return false;
}
else {
// on mets à jour la liste des employés Agresso obtenue
await _repository.UpdateUsersAsync(myUsers);
}
_log.LogInformation(">>> {serviceName} finished its tasks <<<", nameof(ContosoService));
return true;
}
public Task StopAsync(CancellationToken cancellationToken) {
_log.LogInformation(">>> {serviceName} stopped <<<", nameof(ContosoService));
return Task.CompletedTask;
}
}
and I call it from main like this:
public static void Main(string[] args)
{
try {
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex) {
Log.Fatal(ex, ">>> the application could not start <<<");
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host
.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => {
var config = hostContext.Configuration;
if (args.Contains("Alonso")) {
services
.AddHostedService(provider =>
new AlonsoService(
provider.GetService<ILogger<AlonsoService>>(),
provider.GetService<IAlonsoRepository>()));
}
// if there also Cedig in the list, they can be run in parallel
if (args.Contains("Contoso")) {
services
.AddHostedService(provider =>
new ContosoService(
provider.GetService<ILogger<ContosoService>>(),
provider.GetService<IContosoRepository>()));
}
});
Now, the problem, is surely, that the application will not stop once all updates finished.
Is there a way to quickly rewrite the application in order to make it stop after the second service finishes its tasks?
I tried to put the Environment.Exit(0); at the end
public static void Main(string[] args) {
try {
CreateHostBuilder(filteredArgs.ToArray()).Build().Run();
}
catch (Exception ex) {
//Log....
}
Environment.Exit(0); // here
}
but it does not seem to help: the application is still running after all task are completed.
Following #Maxim's suggestion, I found this dirty but working workaround, by injecting the IHostApplicationLifetime and the lastService boolean:
public ConsosoService(
IHostApplicationLifetime hostApplicationLifetime,
// ...
bool lastService)
{ ... }
public async Task StartAsync(CancellationToken cancellationToken)
{
// do the job
if (_lastService)
_hostApplicationLifetime.StopApplication();
// stops the application and cancel/stops other services as well
}
HostedServices are background services. It's the other way around: they can react to application start and stop events, so that they can end gracefully. They are not meant to stop your main application when finished, they potentially live as long as the application does.
I'd say you will be better served with simple Tasks and awaiting all of them. Or send some events when your background jobs finishes its work and handle them in main.
Whatever trigger you may choose you can stop .net app by injecting IHostApplicationLifetime and calling StopApplication() method on it. In earlier versions it's just IApplicationLifetime.
Looking at IHost Interface documentation the method run() does not stop until the host is shutdown. seems that StopAsync() did not stop the service. so Environment.Exit(0); was never reached. maybe use CancellationToken to forcefully end the host, or inject Environment.Exit(0); in ContosoService class if possible even though not optimal.
Here is another approach without need for creating hosted service
using var host = CreateHostBuilder(args).Build();
await host.StartAsync();
using var scope = host.Services.CreateScope();
var worker = scope.ServiceProvider.GetService<Worker>();
await worker!.Run();
await host.StopAsync();
IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices(services => ConfigureServices(services));
void ConfigureServices(IServiceCollection services)
{
//main class which does the work
services.AddScoped<Worker>();
//do some DB operations
services.AddScoped<DbCtxt>();
}
Complete code https://github.com/raghavan-mk/dotnet/tree/main/DIInConsole

MvvmCross Async command lock

I have alot of button in my application. They are placed next to each other. All of the methods are IMvxAsyncCommand type. I figured out some missmatches after tests done by users. I have found duplicate operations - two diffrent buttons are called in almost same time.
What did I do is created my own SafeAsyncCommand class and inheret from MvxAsyncCommand. My goal is to create delay between executes - I want to prevent double click in given delay in below case 0.5s.
There is my work:
public static class SafeCommandSettings
{
public static bool CanExecute { get; private set; }
public static TimeSpan Delay => TimeSpan.FromMilliseconds(500);
static SafeCommandSettings()
{
CanExecute = true;
}
public static async void Pause()
{
if (!CanExecute) return;
CanExecute = false;
await Task.Delay(Delay);
CanExecute = true;
}
}
public class SafeAsyncCommand : MvxAsyncCommand
{
public SafeAsyncCommand(Func<Task> execute, Func<bool> canExecute = null, bool allowConcurrentExecutions = false)
: base(execute, canExecute, allowConcurrentExecutions)
{
}
public SafeAsyncCommand(Func<CancellationToken, Task> execute, Func<bool> canExecute = null, bool allowConcurrentExecutions = false)
: base(execute, canExecute, allowConcurrentExecutions)
{
}
protected override async Task ExecuteAsyncImpl(object parameter)
{
if (!SafeCommandSettings.CanExecute) return;
SafeCommandSettings.Pause();
await base.ExecuteAsyncImpl(parameter);
}
}
public class SafeAsyncCommand<T> : MvxAsyncCommand<T>
{
public SafeAsyncCommand(Func<T, Task> execute, Func<T, bool> canExecute = null, bool allowConcurrentExecutions = false)
: base(execute, canExecute, allowConcurrentExecutions)
{
}
public SafeAsyncCommand(Func<T, CancellationToken, Task> execute, Func<T, bool> canExecute = null, bool allowConcurrentExecutions = false)
: base(execute, canExecute, allowConcurrentExecutions)
{
}
protected override async Task ExecuteAsyncImpl(object parameter)
{
if (!SafeCommandSettings.CanExecute) return;
SafeCommandSettings.Pause();
await base.ExecuteAsyncImpl(parameter);
}
}
I thought this is working but I saw users were able to do it again. Do I miss some knowledge about async methods or static thread safe?
Thanks in advance
In order to do so you can take advantage of MvxNotifyTask that is a wrapper of the Task that watches for different task states and you'll run on your command and do something like this (notice that you don't need the command to be MvxAsyncCommand):
public MvxNotifyTask MyNotifyTaskWrapper { get; private set; }
public MvxCommand MyCommand { get; private set; }
private void InitializeCommands()
{
// this command is executed only if the task has not started (its wrapper is null) or the task is not in progress (its wrapper is not IsNotCompleted)
this.MyCommand = new MvxCommand(() => this.MyNotifyTaskWrapper = MvxNotifyTask.Create(() => this.MyLogicAsync()),
() => this.MyNotifyTaskWrapper == null || !this.MyNotifyTaskWrapper.IsNotCompleted);
}
private async Task MyLogicAsync()
{
// my async logic
}
So as soon the async process is started the command can't be executed again preventing duplicate operations, and you can start it again when that task completes.
If you have to disable multiple commands execution when running some task just add the same CanExecute condition on the different commands or mix conditions of different MvxNotifyTask
Also check that the MvxNotifyTask raises property-changed notifications that you can subscribe to or bind to in your view displaying a "loading" or something like that when performing the operation.
Note: if you are using Mvx < 5.5 you won't have MvxNotifyTask but you can use NotifyTaskCompletion done by Stephen Cleary that is almost the same as MvxNotifyTask and it is from where MvxNotifyTask was based on.
HIH
Instead of delaying things, consider using AsyncLock by Stephen Cleary or lookup Interlocked.CompareExchange.
As far as I can tell from here, you shouldn't use a static CanExecute in your case, as it locks all commands using your "safe" command at once.
And there is the possibility of race conditions, since you aren't changing the value of CanExecute locked.

ASP.NET 5 Middleware "no response received" after adding header

public class MyMiddleware
{
RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
//await context.Response.WriteAsync("Hello!");
await _next(context);
context.Response.Headers.Add("X-ElapsedTime", new[] { "bla" });
}
}
As soon as I add something like a header. I cannot receive any more the response from my Web API controller.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMyMiddleware();
app.UseMvc();
}
Do I need to read first the answer the following middleware "UseMvc" produced?
I just have a very simple Controller method:
// GET: api/values
[HttpGet]
public IEnumerable<string> Get()
{
//Task t = new Task(() => Thread.Sleep(2000));
//t.Start();
return new string[] { "value1", "value2" };
}
I think I found a solution, but it is not actually a full answer:
public class MyMiddleware
{
RequestDelegate _next;
HttpContext _context;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
_context = context;
context.Response.OnStarting(OnStartingCallback, state: this);
await _next(context);
}
public Task OnStartingCallback(object state)
{
_context.Response.Headers.Set("x-bla", "bla");
return Task.FromResult(0);
}
}
I found a reference to: https://github.com/aspnet/Session/blob/master/src/Microsoft.AspNet.Session/SessionMiddleware.cs and tried to build my code according to it.
Anyway this code feels not very safe. Is it really thread safe.
Basically what's happening is that you can't set any headers after anything has been written to the response body.
It is because the headers are being sent before the body and as soon as any body content is set.
To get around it in a proper way would be to buffer the response and don't send anything until all middlewares have been executed so they have a chance to modify the headers. This behavior should be a responsibility of the web server. Unfortunately, I didn't find any useful information how to configure buffering on ASP.NET 5 (IIS or Kestrel).
Your solution seems to be ok, but it's not thread safe. Middlewares are singletons and holding context in a class field may introduce race conditions when multiple concurrent request may hit your server.
You can make it thread safe by passing the context as a state object.
context.Response.OnStarting(OnStartingCallback, state: context);
and then retrieve it in callback by casting object state to HttpContext.

Resources