No duplication work in two instance of simple job processor - asp.net-core

I have a web app (Asp.net Core 2.0) and a simple job processor (.NET Core 2.0) as below.
My web app will add jobs to a database, the processor will get the job every 5 minutes and do some logic.
I wrapped the processor in docker, deployed & run on two servers (there are two instances)
Any solutions to make sure there is no duplicate work here? I want two instances active at the same time.
Simple job processor
while (true)
{
Console.WriteLine("Background worker is running");
//Query job from table job
if (DateTime.UtcNow < job.ExpiredAt)
{
//Call external REST API
//Do something
}
Console.WriteLine($"Background worker is delayed for 5 minutes\r\n");
Task.Delay(JobInterval * 60 * 1000).Wait();
};

You need something to coordinate your workers. You can't just have multiple instances grabbing at the same pool and keep things separate with no duplication of work. Concurrency will eat your lunch. Instead, there should be a coordinating node that assigns tasks out to the other nodes. That's the only way you can handle this.

Related

How do you deploy a long running .NET Core application as an App Service?

I have an application that mimics an equity market. One part of it, generates price changes and POSTS them to a consumer sending roughly 100 price changes roughly ten times a second. The second part of the market exchange takes in orders, executes them randomly and asynchronously sends execution reports back to the same consumer of the price changes.
I want to put this on a App Service, but here's the issue:
I want the price generator to start immediately and run continuously.
The order execution only needs to run when orders are sent (asynchronously) and all the orders have been executed or cancelled. Then it can shut down until another order is received.
It seems like I'm forced into one of two buckets and neither applies to what I want to do. A Web Job appears to work like a Service in Windows 11. It will start up immediately and run until you shut it down, but it doesn't have the logic to handle an ASP-type controller.
Deploying as an App Service works as long as I wake it up by POSTing an order, but the price feed doesn't start until I send the order.
So here's the question: How do you deploy a .NET Core application as an App Service and have it start automatically (without waking it up with an initial HTTP call)?
According to your description, I suggest you could consider modifying the price feed as a background service inside the .net core application. The background tasks can be implemented as hosted services. A hosted service is a class with background task logic that implements the IHostedService interface.
It contains the StartAsync method. The StartAsync(CancellationToken) contains the logic to start the background task. StartAsync is called before:
The app's request processing pipeline is configured.
The server is started and IApplicationLifetime.ApplicationStarted is triggered.
More details, you could refer to this article.
Besides, I suggest you could also set the Azure web app's configuration as alwayson.

.net core multiple dynamic consumers of a BlockingCollection

I am looking for a reliable and easy pattern to consume (execute) background tasks in .net core in parallel.
I found this https://stackoverflow.com/a/49814520/1448545 answer, but the problem is there is always single consumer of the tasks.
What if there is 1 new task to perform per 100ms, while each task takes 500ms to complete (e.g. long running API call). In such case the tasks will pile up.
How to make it dynamic, so if there is more items in BlockingCollection<TaskSettings> _tasks the .net core will create more tasks executors (consumer) dynamically?

Run 1 task with IHostedService

What am I doing wrong?
IHostedService classes are registered in ASP.net core HostBuilder.
Then run continuously in the background, even if they have no work to do.
There is no way to pass them work, so I suppose they must pick up tasks from a dynamic store eg database
So it seems they poll mostly. Or run short interval timers; looking for work
Then when they get jobs they can only do 1 at a time.
So if my users (100+) run reports on a Friday (or what ever day they wish) the service just polls the database for 6.5 days and then is throttled for 0.5 days to get the 100+ reports generated.
So how can I
control the starting of the IHostedservice service
Run more that 1 instance of the IHostedservice service
Send tasks in the form of data to the IHostedservice service (instance)
Furthur to this I will need 10+ different types of IHostedService. (10+ different polling types)
So running them in the backgorund just to poll the database takes up CPU cycles on both web server and database server
control the starting of the IHostedservice service
You can't. The start and stop of IHostedService is controlled by Host itself. See official docs
Run more that 1 instance of the IHostedservice service
As the IHostedService is run by host itself, I believe you won't actually want to start multiple IHostedService, but instead you're seeking a way to start tasks in parallel way and then wait all the tasks to be done. IMO, a better way is to create a delegate that returns a task which consists of several sub tasks. This sub tasks will run in a parallel way.
Send tasks in the form of data to the IHostedservice service (instance)
The official docs has an excellent example for this:
You can wrap your task with a delegate (which is a form of data).
When you want to send this task to IHostedService somewhere (e.g. in Controller), just enqueue your task wrapper (delegate instance) into the queue service.
The HostedService will wait until there's a task in the queue, dequeue a work item, and execute that delegate instance.
If you want to start several work items at the same time, just dequeue multiple work items and then start these tasks with theTask.WhenAll :
await Task.WhenAll(...);
For more details, see parallel-programming

How to use a different named worker pool in same verticle?

I have one verticle in my service which takes in the http requests and uses executeBlocking to talk to MySQL db. I am using named worker pool to interact with DB. Now, for pushing the application metrics (using a lib. which is blocking) I want to use a different named worker pool. As I don't want the DB operations to be interrupted with metrics so I want to have a separate worker pool.
I could use event bus and use a worker verticle to push the metrics but as that has overhead of transformation to the JsonObject, I want to use executeBlocking itself from the same verticle.
As mentioned here https://groups.google.com/d/msg/vertx/eSf3AQagGGU/9m8RizIJeNQJ
, the worker pool used in both the cases is same. So, will making a new worker verticle really help me in decoupling the threads used for DB operation and the ones used to push metrics.
Can anyone help me with a better design choice or how can I use a different worker pool if I use the same verticle ?
Try the following code (written in Kotlin, but you get the idea):
val workerExecutor1 = vertx.createSharedWorkerExecutor("executor1", 4)
val workerExecutor2 = vertx.createSharedWorkerExecutor("executor2", 4)
workerExecutor1.executeBlocking(...) // execute your db code here
workerExecutor2.executeBlocking(...) // execute your metrics code here
Don't forget to close the workerExecutor once it's not needed:
workerExecutor1.close()

How should i design my workflow so that taks can run parallel

how to design parallel processing workflow
I have a scenarial case about data analysis.
There are four steps basicly:
pick up task either read from a queue or receive a message throught API (web service maybe) to trigger the service
submit request to remote service base on the parameters from step 1
wait from remote service finished and download
perform process on the data that downloaded from step 3
the four step above looks like a sequence workflow.
my question is that how can i scale it out.
every day i might need to perform hundreds to thousands of this task.
if i can do them in parallel, that will help a lot.
e.g run 20 tasks at a time.
so can we config windows workflow foundation to run parallel?
Thanks.
You may want to use pfx (http://www.albahari.com/threading/part5.aspx), then you can control how many threads to make for fetching, and using PLINQ I find helpful.
So, you loop over the list of urls, perhaps reading from a file or database, and then in your select you can then call a function to do the processing.
If you can go into more detail as to whether you want to have the fetching and processing be on different threads, for example, it may be easier to give a more complete answer.
UPDATE:
This is how I would approach this, but I am also using ConcurrentQueue (http://www.codethinked.com/net-40-and-system_collections_concurrent_concurrentqueue) so I can be putting data into the queue while reading from it.
This way each thread can dequeue safely, without worrying about having to lock your collection.
Parallel.For(0, queue.Count, new ParallelOptions() { MaxDegreeOfParallelism = 20 },
(j) =>
{
String i;
queue.TryDequeue(out i);
// call out to URL
// process data
}
});
You may want to put the data into another concurrent collection and have that be processed separately, it depends on your application needs.
Depending on the way your tasks and workflow is modeled you can use a Parallel activity and create different branches for the different tasks to be performed. Each branch has its own logic and the WF runtime will start a second WCF request to retrieve data as soon as it is waiting for the first to respond. This requires you to model the number of branches explicitly but allows for different activities in each branch.
But from you description it sounds like you have the same steps for each task and in that case you could model it using a ParallelForEach activity and have that iterate over a collection of tasks. Each task object would need to contain all the information used for the request. This requires each task to have the same steps but you can put in as many tasks as you want.
What works best really depends on your scenario.