Asynchronous logging Service in Spring Boot - asynchronous

I am using 1.5.6.RELEASE to create REST Api that shall store user actions in MS SQLServer database. To make this user action service asynchronous, I have configured #EnableAsync in my main class.
#EnableAsync
public class WebApp extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(WebApp.class, args);
}
}
#Async
public void saveAction(ActionInfo event) {
actionDataService.save(event);
}
I want to ensure that whatever happens(Server crashes, database goes down etc), user action posted by the client through Rest API service must be saved in database (may be through retry when database comes online or Application server starts again).
Proposed Solutions
Followings are the solutions:
1) Write AsyncUncaughtExceptionHandler to handle exceptions that retries again to save user action. But if Server crashes, the user action objects shall be lost.
2) Use JMS queues to store user action. If Server crashes, the JMS queue should not be lost. It must be able to retry it when server restores. (Just an idea, does not have much knowledge about queues)
Can you please suggest?

Related

.NET Generic Host - Is it possible to stop and restart a host?

Consider this extremely simple .NET Core 3.1 (and .NET 5) application with no special config or hosted services:
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
internal class Program
{
public static async Task Main(string[] args)
{
var builder = Host.CreateDefaultBuilder(args);
builder.UseWindowsService();
var host = builder.Build();
var fireAndforget = Task.Run(async () => await host.RunAsync());
await Task.Delay(5000);
await host.StopAsync();
await Task.Delay(5000);
await host.RunAsync();
}
The first Run (sent as a background fire and forget task only for the purpose of this test) and Stop complete successfully. Upon calling Run a second time, I receive this exception:
System.AggregateException : 'Object name: 'EventLogInternal'.Cannot access a disposed object. Object name: 'EventLogInternal'.)'
If I do the same but using StartAsync instead of RunAsync (this time no need for a fireAndForget), I receive a System.OperationCanceledException upon called StartAsync the second time.
Am I right to deduce that .NET Generic Host aren't meant to be stopped and restarted?
Why do I need this?
My goal is to have a single application running as a Windows Service that would host two different .NET Generic Host. This is based on recommendation from here in order to have separate configuration and dependency injection rules and message queues.
One would stay active for all application lifetime (until the service is stopped in the Windows services) and would serve as a entry point to receive message events that would start/stop the other one which would be the main processing host with full services. This way the main services could be in "idle" state until they receive a message triggering their process, and another message could return them to idle state.
The host returned by CreateDefaultBuilder(...).Build() is meant to represent the whole application. From docs:
The main reason for including all of the app's interdependent resources in one object is lifetime management: control over app startup and graceful shutdown.
The default builder registers many services in singleton scope and when the host is stopped all of these services are disposed or switched to some "stopped" state. For example before calling StopAsync you can resolve IHostApplicationLifetime:
var appLifetime = host.Services.GetService<IHostApplicationLifetime>();
It has cancellation tokens representing application states. When you call StartAsync or RunAsync after stopping, all tokens still have IsCancellationRequested set to true. That's why the OperactionCancelledException is thrown in Host.StartAsync.
You can list other services during configuration:
For me it sounds like you just need some background jobs to process messages but I've never used NServiceBus so I don't know how it will work with something like Hangfire. You can also implement IHostedService and use it in the generic host builder.
I'm doing something like:
do
{
using IHost host = BuildHost();
await host.RunAsync();
} while (MainService.Restart);
with MainService constructor:
public MainService(IHostApplicationLifetime HostApplicationLifetime)
MainService.Restart is a static bool set by the MainService itself in response to some event which also calls HostApplicationLifetime.StopApplication().

How to seek to kafka record from starting after an API call in spring boot webservice

I have a spring-boot Kafka project which is a web-service exposing API to get Kafka message in response.
What i want is whenever i call the rest end point the Kafka should start searching from beginning it does it as i used earliest in auto-reset config but i have to start server again and again to make it listen to Kafka from starting.
#KafkaListener(topics = {"topic"})
public void storeMessagesMessages(ConsumerRecord record) {
if (record.value().toString().contains(uuid) {
this.messageToBeReturnedByApi = record.value()
}
}
Or i can say i want this listener part to be invoked only when i call web service endpoint
Your listener should extend AbstractConsumerSeekAware; you can then perform arbitrary seek operations. See https://docs.spring.io/spring-kafka/docs/2.6.2/reference/html/#seek

dotnet console app, using generic host, HostedService, Windows Task Scheduler stays in running state

Trying to figure out why my console app won't stop running.
Using the following approach in a dotnet core application main method:
await new HostBuilder().
...
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<MyHostedService>();
})
.UseConsoleLifetime()
.Build()
.RunAsync();
Publishing and scheduling that task from the Windows Task Scheduler using the following settings works:
All good so far. All code is properly executed. However, the task stays running, the process never ends. (not even after pressing refresh on the UI of the task scheduler)
Is this expected? If not, how do I get the process to terminate?
If expected, does it still make sense then, to use Generic Host / Hosted Service in a scheduled console app that just starts, runs, and stops?
Answer based on Microsoft.Extensions.Hosting 2.2.0
This behavior is expected, due to your usage of the Generic Host:
It keeps running until shut down or disposed, and you have no shutdown mechanism in place. I assume you expect the Generic Host to shut down after IHostedService.StartAsync(CancellationToken) of your MyHostedService ran to completion. This is not the case, because there might be other IHostedService implementations registered and executed in sequence, and/or a long running BackgroundService which returns control when its ExecuteAsync(CancellationToken) is not completing synchronously to allow other services to run in parallel.
To stop your application gracefully after your MyHostedService completes when running the host via RunAsync, you should constructor-inject the IApplicationLifetime into your MyHostedService and call StopApplication after your Task has completed.
internal class MyHostedService : IHostedService
{
private readonly IApplicationLifetime _appLifetime;
public MyHostedService(IApplicationLifetime appLifetime)
{
_appLifetime = appLifetime;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await Task.Delay(1000); //your scheduled work
_appLifetime.StopApplication();
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Also, the application may be stopped via either AppDomain.CurrentDomain.ProcessExit or Console.CancelKeyPress, both events are subscribed to by the ConsoleLifetime, which is pre-registered as the default lifetime implementation.
You can read more about lifetime management in the docs.
Microsoft.Extensions.Hosting 3.0.0 - currently in preview - marked IApplicationLifetime obsolete and recommends using IHostApplicationLifetime instead

Azure web job singleton function is locked

I am using Azure web job to run some logic continuously. The function is a singleton function. However, I am getting "Waiting for lock" message after I tried to run this function after a restart of the web app. Does it mean that another instance of the same function is keeping the lock? How can I resolve this?
The function:
namespace Ns
{
public class Functions
{
[Singleton]
[NoAutomaticTriggerAttribute]
public static async Task ProcessMethod()
{
while(true){
//process logic here
await Task.Delay(TimeSpan.FromSeconds(20));}
}
}
}
The main program:
namespace ns
{
class Program
{
static void Main()
{
var host = new JobHost();
host.RunAndBlock();
}
}
}
The message that I got:
According to the Singleton attribute description the lock is adquired during function execution by a Blob lease.
If another function instance is triggered while this function is
running it will wait for the lock, periodically polling for it.
If you have more than one instance of your App Service Plan, this means that there are more than one Webjob and thus the Dashboard might be showing the locked status of the other Webjobs while one is running.
You can view the blob lease locks that are created on your storage account.
Another option is to try Listener Singletons but I never tried it with Manual triggers.
I disabled the production function in Azure and set the listenerlockPeriod to 15 seconds as described above.
This lessened the locking behavior significantly.

Need advice in develop a queue job to interact between two application

Currently i have a web application and a wins form application in my server. Basically, the web application will receive request from user and this request will be send to the wins form application to proceed (wins form need about 1 minute to complete a request).
Let say 2 users send a request at the same time via web application, I need to develop a queue job to maintain the request in sequence.
1) User A make a request > request will be store into a queue job
2) User B make a request > request will be store into a queue job
3) The queue job will send the first request to the wins form. Once first request is complete, then will follow by the second request
So my question is, this queue job should be develop inside the web application? Or it should be develop in a stand alone wins form?
Any example code for create a queue job in ASP.NET?
Or anyone can suggest a better solution?
using System.Collections.Generic;
Queue<task> Q = new Queue<task>();
public void Proccess_Request(string info)
{
task t = new task();
t.INFO = info;
Q.Enqueue(task);
}
public void DoWork()
{
//
while (Q.Count > 0)
{
task t = Q.Dequeue();
//Process task t
}
}
public class task
{
public string INFO { get; set; }
// Whatever task properties you need
}
You will need to build the service that accepts form data and passes it to method Process_Request. You will also need to call method DoWork either once every x minutes, or have it listen for Process_Request to fire.
Or you can use MSMQ and do it that way. the ASP.NET site sends a message to the queue, the winforms app (or service) is bound to the queue so when messages come into the queue, it will pick it up, process it and let it be done until no more messages in the queue.
You can handle cross domain queue communication with MSMQ, for example.

Resources