I am newbie to .NET Core and asynchronous programming. I am trying to implement a console application to do the following:
The console application should work as intermediator between two external APIs. eg. API-1 and API-2.
It should call API-1 after every 10 milliseconds to get data.
Immediately call API-2 to submit the data that is received from API-1.
Console Application needs to wait for API-1 to receive data, but does not have to wait for the response from API-2.
Below is my code. It not working as expected. At first it invokes API-1 in 10 milliseconds as expected, but after that its invoking API-1 ONLY AFTER it receives response from API-2.
So assume API-2 takes 20 seconds, API-1 is also getting invoked after 20 seconds.
How do I make API-2 call asynchronous so it does not have to wait for API-2 response?
namespace ConsoleApp1
{
public class Program
{
private static Timer _timer;
private const int TIME_INTERVAL_IN_MILLISECONDS = 10; // 10 milliseconds
private const int API2_DELAY = 20000; // 20 seconds
public static void Main(string[] args)
{
Dowork().Wait();
Console.WriteLine("Press Any Key to stop");
Console.ReadKey();
Console.WriteLine("Done");
}
private static async Task Dowork()
{
var data = new SomeData();
_timer = new Timer(CallAPI1, data, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
await Task.Yield();
}
private static async void CallAPI1(object state)
{
var data = state as SomeData;
Console.WriteLine("Calling API One to get some data.");
data.SomeStringValue = DateTime.Now.ToString();
await CallAPI2(data);
_timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}
private static async Task CallAPI2(SomeData data)
{
Console.WriteLine("Calling API Two by passing some data received from API One " + data.SomeStringValue);
// the delay represent long running call to API 2
await Task.Delay(API2_DELAY);
}
}
}
POCO class
namespace ConsoleApp1
{
public class SomeData
{
public string SomeStringValue { get; set; }
}
}
Also note that API-1 and API-2 will be developed in ASP.NET Core 1
Update1
Let me rephrase above sentence. The API-1 would be developed in .Net core but API-2 would be windows workflow service. That means we can make multiple calls to WF. The WF will persist the requests and process one at a time.
Update2
After going through all the answers and links provided. I am thinking to use windows service as intermediator instead of console application. Right now .Net core does not support window service but has this nuget-package that can host .Net core inside windows service or I might use classic windows service using 4.6.2. I guess I can do the asyncrous implementation inside windows service as well.
There are a lot of things that I would do differently in this situation. Rather than using a timer I would use Task.Delay, also - I would most certainly wait for API2 to complete before attempting to throw more data at it. Additionally, I would ensure that my async methods are Task or Task<T> returning, notice your CallAPI1 call isn't, I understand it's a timer callback -- but that is another issue.
Consider the following:
async Task IntermediateAsync()
{
Console.WriteLine("Press ESC to exit...");
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
var result = await _apiServiceOne.GetAsync();
await _apiServiceTwo.PostAsync(result);
// Wait ten milliseconds after each successful mediation phase
await Task.Delay(10);
}
}
This will act in the following manner:
Print a line instructing the user how to exit
Start loop
Get the result of API1
Pass the result to API2
Wait 10 milliseconds
[Step 2]
Finally, this is the same suggestion regardless of whether or not your using .NET Core. Any API interactions should follow the same guidelines.
Notes
Using a fire-and-forget on the second API call is simply setting your code up for failure. Since it is an API call there is more than likely going to be some latency with the I/O bound operations and one should assume that a tight loop of 10 milliseconds is only going to flood the availability on that endpoint. Why not simply wait for it to finish, what reason could you possibly have?
Remove the await when calling API2
private static async void CallAPI1(object state)
{
var data = state as SomeData;
Console.WriteLine("Calling API One to get some data.");
data.SomeStringValue = DateTime.Now.ToString();
//Before this will cause the program to wait
await CallAPI2(data);
// Now it will call and forget
CallAPI2(data);
_timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}
Edit:
As David points out, of course there is many way to solve this problem. This is not a correct approach to solve your problem.
Another method of doing things is use quartz.net
Schedule API1 as a repeating job
When API1 is done, schedule another job to run API2 as a standalone job
This way when API2 fails you can replay/repeat the job.
Related
I need to add delay to some code block. I am using Task ContinueWith to achieve that, it works as expected when tested on my machine but the deployed code is not working.
public void DailyReminder()
{
//Do somethings
System.Threading.Tasks.Task.Delay(300000).ContinueWith(t => EmailAlert()); //This should not block UI
//Do more things, this should not wait for 300000 ms to get excecuted
}
public void EmailAlert()
{
//Send Email
}
For Example i need the below code to produce A B C and D only after the 5 sec delay -
using System;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("A");
EmailAlert();
Console.WriteLine("C");
}
private static async Task EmailAlert()
{
Console.WriteLine("B");
await Task.Delay(5000);
Console.WriteLine("D");
}
}
}
You should separate your EmailAlert (which is a fire-and-forget task) and the logic that is not dependent on the task.
public void DailyReminder()
{
// A discard pattern to make it explicit this is a fire-and-forget
_ = EmailAlert();
// Additional code that does not depend on the preceding task
}
public async Task EmailAlert()
{
await Task.Delay(300_000);
// await Some email sending logic
}
it works as expected when tested on my machine but the deployed code is not working.
If you're using some kind of shared or cloud hosting, it's normal to have your app shut down when it's done servicing requests for some time. This is why fire-and-forget on ASP.NET is dangerous.
Since you definitely want your email to be sent, fire-and-forget is not an appropriate solution. Instead, you want a basic distributed architecture:
Instead of sending the email from ASP.NET, serialize it to a message sent to a durable queue.
Have a separate background process read that queue and send the actual email.
I'm not sure of where in your code you are trying to create this delay, but you normally don't have the control over how long a thread will be alive when deploying your application to a server.
Normally a thread is created when a user sends a request to the application, and when it returns its response the thread will be stopped.
Also, the web server may close down the entire application when there's no traffic for a while.
The solution for these long running methods is to use Worker services.
You can read more from the documentation at https://learn.microsoft.com/en-us/dotnet/core/extensions/workers
You try use case this :
public void DailyReminder()
{
//Do somethings
System.Threading.Tasks.Task.Delay(300000).ContinueWith(t => EmailAlert()).Wait(); //This should not block UI
//Do more things, this should not wait for 300000 ms to get excecuted
}
public void EmailAlert()
{
//Send Email
}
I have a bunch of remoting calls that are all synchronous (3rd party library). Most of them take a lot of time so I'm not able to use them more often then about 5 to 10 times per second. This is too slow because I need to call them at least 3000 times every couple of minutes and many more if the services was stopped for some time. There is virtually no CPU work on the client. It gets the data, checks some simple conditions and makes another call that it has to wait for.
What would be the best way to make them async (call them in an async fashion - I guess I need some async wrapper) so that I can make more requests at the same time? Currently It's limited by the number of threads (which is four).
I was thinking about calling them with Task.Run but every article I read says it's for CPU bound work and that it uses thread-pool threads. If I get it correctly, with this approach I won't be able to break the thread limit, will I?. So which approach would actually fit best here?
What about Task.FromResult? Can I await such methods asynchronously in a greater number than there are threads?
public async Task<Data> GetDataTakingLotsOfTime(object id)
{
var data = remoting.GetData(id);
return await Task.FromResult(data);
}
I was thinking about calling them with Task.Run but every article I read says it's for CPU bound work and that it uses thread-pool threads.
Yes, but when you're stuck with a sync API then Task.Run() might be your lesser evil, especially on a Client.
Your current version of GetDataTakingLotsOfTime() is not really async. The FromResult() merely helps to suppress the Warning about that.
What about Task.FromResult? Can I await such methods asynchronously in a greater number than there are threads?
Not clear where your "number of threads" idea comes from but yes, starting a Task method and awaiting it later essentially runs it on the ThreadPool. But Task.Run is clearer in that respect.
Note that that does not depend on the async modifier of the method - async is an implementation detail, the caller only cares that it returns a Task.
Currently It's limited by the number of threads (which is four).
This needs some explaining. I don't get it.
You are executing a remote call, and your thread needs to wait idly for the result of the remote call. During this wait your thread could do useful things, like executing other remote calls.
Times when your thread is idly waiting for other processes to finish, like writing to a disk, querying a database or fetching information from the internet are typically situations where you'll see an async function next to a non-async function: Write and WriteAsync, Send and SendAsync.
If at the deepest level of your synchronous call you have access to an async version of the call, then your life would be easy. Alas it seems that you don't have such an async version.
Your proposed solution using Task.Run has the disadvantage of the overhead in starting a new thread (or running one from the thread pool).
You could lower this overhead by creating a workshop object. In the workshop, a dedicated thread (a worker), or several dedicated threads are waiting at one input point for an order to do something. The threads performs the task and posts the result at the output point.
Users of the workshop have one access point (front office?) where they post the request to do something, and await for the result.
For this I used System.Threading.Tasks.Dataflow.BufferBlock. Install Nuget package TPL Dataflow.
You can dedicate your workshop to accept only work to GetDataTakingLotsOfTime; I made my workshop generic: I accept every job that implements interface IWork:
interface IWork
{
void DoWork();
}
The WorkShop has two BufferBlocks: one to input work requests and one to output finished work. The workshop has a thread (or several threads) that wait at the input BufferBlock until a job arrives. Does the Work, and when finished posts the job to the output BufferBlock
class WorkShop
{
public WorkShop()
{
this.workRequests = new BufferBlock<IWork>();
this.finishedWork = new BufferBlock<IWork>();
this.frontOffice = new FrontOffice(this.workRequests, this.finishedWork);
}
private readonly BufferBlock<IWork> workRequests;
private readonly BufferBlock<IWork> finishedWork;
private readonly FrontOffice frontOffice;
public FrontOffice {get{return this.frontOffice;} }
public async Task StartWorkingAsync(CancellationToken token)
{
while (await this.workRequests.OutputAvailableAsync(token)
{ // some work request at the input buffer
IWork requestedWork = this.workRequests.ReceiveAsync(token);
requestedWork.DoWork();
this.FinishedWork.Post(requestedWork);
}
// if here: no work expected anymore:
this.FinishedWork.Complete();
}
// function to close the WorkShop
public async Task CloseShopAsync()
{
// signal that no more work is to be expected:
this.WorkRequests.Complete();
// await until the worker has finished his last job for the day:
await this.FinishedWork.Completion();
}
}
TODO: proper reaction on CancellationToken.CancellationRequested
TODO: proper reaction on exceptions thrown by work
TODO: decide whether to use several threads doing the work
FrontOffice has one async function, that accepts work, sends the work to the WorkRequests and awaits for the work to finish:
public async Task<IWork> OrderWorkAsync(IWork work, CancellationToken token)
{
await this.WorkRequests.SendAsync(work, token);
IWork finishedWork = await this.FinishedWork.ReceivedAsync(token);
return finishedWork;
}
So your process created a WorkShop object and starts one or more threads that will StartWorking.
Whenever any thread (inclusive your main thread) needs some work to be performed in async-await fashion:
Create An object that holds the input parameters and the DoWork function
Ask the WorkShop for the FrontOffice
await OrderWorkAsync
.
class InformationGetter : IWork
{
public int Id {get; set;} // the input Id
public Data FetchedData {get; private set;} // the result from Remoting.GetData(id);
public void DoWork()
{
this.FetchedData = remoting.GetData(this.Id);
}
}
Finally the Async version of your remote
async Task<Data> RemoteGetDataAsync(int id)
{
// create the job to get the information:
InformationGetter infoGetter = new InformationGetter() {Id = id};
// go to the front office of the workshop and order to do the job
await this.MyWorkShop.FrontOffice.OrderWorkAsync(infoGetter);
return infoGetter.FetchedData;
}
I am building a Windows Service to read records from a table, pass record data to a WCF Service, wait for its response and update the same record in the database depending on the response from the WCF Service. This process will continue for all the records and once all the records are processed, I need to delay further execution of code for n number of minutes. After the n minutes has elapsed, I need to call the same code to read records from the table again and process them and once all the records are processed, delay execution again for n number of minutes. This need to happen infinitely and the most important point is that all the executions should happen synchronously including the delayed execution, I want to completely avoid using Threading or async/await or any other asynchronous programming techniques.
After searching for while, I have learned that with .NET Framework 4.5, the recommended way is using Task.Delay() method without using asycn/await keywords to add a delay synchronously. So I have created a simple console application having a recursive method with an infinite loop:
class Program
{
static void Main(string[] args)
{
RecursiveMethod();
}
public static void RecursiveMethod()
{
while (true)
{
DoWork();
Console.WriteLine("Task delayed...");
Task.Delay(3000).Wait();
Console.WriteLine("Calling method again recursively...");
RecursiveMethod();
}
}
public static void DoWork()
{
//Do some work
Console.WriteLine("Work Completed.");
}
}
The above code seems to be working fine but I faced big issues when implementing System.Timers.Timer in another windows service, after running properly for two days, the Timer completely stopped working without throwing any exception, so no error was logged which is very frustrating.
I want to avoid such situations, so what is best way to implement Task.Delay() for simple synchronous code? The delay will be set to 2 hours so I want to also handle situations where the Task.Delay() will get garbage collected or removed from memory or stops working on its own (without throwing any exception) and restart the whole process again.
Just use Thread.Sleep(3000). Not sure why you want to avoid that. Your code is sync, so you shouldn't be using Task.
Also, Task.Delay uses a Timer. So not sure if that's going to solve your problem.
I'd try and figure out why the Timer object stopped working. That doesn't sound right.
Was your timer callback wrapped with a try catch?
As others have noted, Task.Delay is not appropriate here, since your code is not asynchronous. Also, you already have an infinite loop (while (true)), so there is no need for recursion:
class Program
{
static void Main(string[] args)
{
while (true)
{
DoWork();
Console.WriteLine("Task delayed...");
Task.Sleep(3000);
}
}
public static void DoWork()
{
//Do some work
Console.WriteLine("Work Completed.");
}
}
I am modifying an old, large (and un-documented) program in C# that uses an API to talk on a serial bus.
Is there some way of letting OnIndication trigger SendRepeatRequest to continue?
I would like to avoid polling a flag with wait Xms as response time varies greatly and I need quick responses.
//Pseudocode
public void SendRepeatRequest(int X)
{
SendToAPI();
// Wait until API responds, usually a few ms but can take 1-2min
// loop X times
}
//this is activated by the API response
public void OnIndication()
{
// Handle request from API...
// Tell SendRepeatRequest to continue
}
Do you have any suggestions on how to do this?
Thanks!
You may want to look into the Task library (introduced in .NET 4.0 under the System.Threading.Tasks namespace). It has a variety of threading operations to do this pretty easily.
I believe the following section might help (or get you started).
public void OnIndication()
{
Task doWork = new Task(() =>
{
// Handle request
});
Action<Task> onComplete = (task) =>
{
SendRepeatRequest(X, args)
};
doWork.Start();
doWork.ContinueWith(onComplete, TaskScheduler.FromCurrentSynchronizationContext());
}
C# ASP.NET 3.5
Is it possible to "fire and forget" a method in a web service that is not asynchronous or one-way?
There is a method that returns a value (after some processing), which I don't need. It is used by another group (who wrote the service). Basically, it just notifies that user x did action y. I just need to call the method and move on without waiting for the result.
I tried using a BackgroundWorker() with RunWorkerAsync, but the method does not fire for some reason. I cannot change the web service method as I have no access to their code. Should I be using BackgroundWorker, Invoke, ThreadPool, something else? I don't need the result returned, and I don't need to know if it fails. Basically, call the method, and if it works, great. If not, I don't want to stop or slow processing down.
public static void Test()
{
var worker = new BackgroundWorker();
worker.DoWork += Test2;
worker.RunWorkerAsync(new object[] {12345, "test"});
}
private static void Test2(object sender, DoWorkEventArgs e)
{
// Write to log that we got into the method - does not
object[] args = e.Argument as object[];
int num = Convert.ToInt32(args[0]);
string name = (string)args[1];
// call web service method here....
}
Intsead of using Background Worker you can try the following
public static void Test()
{
System.Threading.ThreadPool.QueueUserWorkItem(delegate
{
Test2(new object[] { 12345, "test" });
});
}
private static void Test2(object data)
{
// Write to log that we got into the method - does not
object[] args = data as object[];
int num = Convert.ToInt32(args[0]);
string name = (string)args[1];
// call web service method here....
}
The feature that is requested, by definition IS WCF OneWay. It is impossible to implement the required behavior completely client-side.
IIS by default (a common host of WCF services) is allowed to kill any process that was kicked off by a closed connection. This means that the client must stay connected for the duration of the process (which in effect means waiting for the result). Additionally it is possible the request can timeout and the "fire and forget" process is killed off.
If you only want to reduce the resources taken up at the client to the minimum whilst the request is in flight I would run the request asynchronously. If you only have access to .net<=4.0 then the easiest way to do this is to generate the async calls (I mean APM async and NOT async/await/TPL async) using the "add service reference" option and tick the "generate async methods" option.
You would have to also learn the APM programming model (which is pretty nasty).
Alternatively you could run the WCF call on a separate Thread. But note, this uses significant additional resources.
There is a document here on Asysn/Sync wfc calls. http://msdn.microsoft.com/en-us/library/ms734701.aspx.