Reputation: 34089
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.
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.
Upvotes: 0
Views: 8395
Reputation: 555
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
This way when API2 fails you can replay/repeat the job.
Upvotes: 0
Reputation: 24525
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:
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?
Upvotes: 2