I've the following code, used to test the Task framework on C#
static void Main(string[] args)
{
Task<string> task1 = AsyncA();
task1.ContinueWith(Print);
Task<string> task2 = AsyncB();
task2.ContinueWith(Print);
Task.WaitAll(new Task[] {task1, task2});
}
static async Task<string> AsyncA()
{
Thread.Sleep(1500);
return "A";
}
static async Task<string> AsyncB()
{
Thread.Sleep(430);
return "B";
}
static async void Print(Task<string> str)
{
Console.WriteLine(str.Result);
}
My output is the following:
A
B
What am I doing wrong?
Thanks in advance.
you are running the methods AsyncA and AsyncB synchronously. If you are using async you need to await the end of a task. Change your methods to
static async Task<string> AsyncA()
{
await Task.Delay(1500);
return "A";
}
static async Task<string> AsyncB()
{
await Task.Delay(430);
return "B";
}
and you will get your expected output of
BA
For further reference have a look on the MSDN example
EDIT:
For the sake of completeness you should also change the Print method in the same manner, otherwise it also is running synchronously up to now.
Since in this method you get the task via the parameter you can actually await the result directly in the Console.WriteLine method:
static async void Print(Task<string> str)
{
Console.WriteLine(await str);
}
Firstly, when using asynchronous methods, it's generally more accepted to use the awaitable Task.Delay(ms) rather than Thread.Sleep(ms).
In the MSDN documentation, the ContinueWith(task) method:
Creates a continuation that executes asynchronously when the target Task completes.
For this reason, only once task1 is completed, it will execute the remainder of the code - this is why your ouput is A B rather than B A.
By using Task.Delay(ms) and awaiting the methods as opposed to using ContinueWith(task), you'll get your expected output.
Related
There are couple of durable functions that call each other.
Main orchestration -> Sub orchestration -> Activity -> Helper async method
Each func has ILogger dependency and log on function start and on function end.
Both orchestrators duplicates "on start" message for some reason. (See pic)
Activity does not have this effect. (See pic)
Ran example below many times - same story.
I am also sure that the whole process has been triggered once.
Is this a bug in orchestrators or expected behavior?
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
namespace Issues
{
public static class Log_Issue
{
[FunctionName("Main")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context,
ILogger log)
{
try
{
log.LogWarning("Main Start");
await context.CallSubOrchestratorAsync("Sub", null);
log.LogWarning("Main End");
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
[FunctionName("Sub")]
public static async Task RunSubOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context,
ILogger log)
{
log.LogWarning("Sub Start");
var data = await context.CallActivityAsync<string>("Activity", null);
log.LogWarning("Sub End");
}
[FunctionName("Activity")]
public static async Task<string> GetDataActivity([ActivityTrigger] string name, ILogger log)
{
log.LogWarning("Activity Start");
var data = await GetDataAsync("https://www.google.com");
log.LogWarning("Activity End");
return data;
}
[FunctionName("Start")]
public static async Task<IActionResult> HttpStart(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]
HttpRequestMessage req,
[DurableClient] IDurableOrchestrationClient starter,
ILogger log)
{
var instanceId = await starter.StartNewAsync("Main", null);
log.LogWarning($"Started orchestration with ID = '{instanceId}'.");
return new OkResult();
}
private static async Task<string> GetDataAsync(string url)
{
var httpClient = new HttpClient();
using var request = new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Get,
};
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
}
This is expected. For example on await context.CallActivityAsync("Activity", null); The code pauses itself and may even be loaded out of memory (in order to save on cost).
Then the orchestrator waits for an event to be placed in another Azure Storage Table which the activity creates, this may occur many days later. For activities they are usually very instant but it still waits for this event to occur.
When that happens the code needs to start from where it last stopped but there is no way to do that. Therefor the code reruns from the beginning but instead of waiting for the activity to finish again it first looks in the table and sees that we already have done this activity and can continue running. If the activity function returned some value it would be returned from the await call. During both runs of the orchestrator it would log but since we only go inte the activity ones that would only be logged ones.
This is why orchestrators have to be deterministic since e.g. a random value on the first run would not be the same as during the second run. Instead we would put the random.Next() into an activity funtion so that the value is saved to Azure Table Storage to be used on subsequent reruns. The orchestrator could also be waiting for some external events which normal functions create. E.g someone has to verify their email account which could take some number of days and this is why durable functions can unload themself and restart when they are triggered by the event.
All that #FilipB said is true. It is just missing the actual code to solve it ;)
[FunctionName("Main")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context,
ILogger log)
{
log = context.CreateReplaySafeLogger(log); // this is what you should use at the start of every Orchestrator
I try to call ShowDialogAsync in a synchron code. I'm not very familiar with async programming. If I run this code, I end up in a deadlock. If I change Command to TaskCommand, it will work, but I have to change all Code to async.
public MainWindow()
{
InitializeComponent();
Abc = new Command(() => Asd());
}
public Command Abc { get; set; }
private void Asd()
{
var b = StartDialog(true).GetAwaiter().GetResult();
}
private async Task<bool> StartDialog(bool isMultiple)
{
await ServiceLocator.Default.ResolveType<IUIVisualizerService>().ShowDialogAsync<PersonVm>(new PersonM());
return true;
}
Here I have used the answer from here.
Could someone help me please?
The recommended way is to migrate your code to async. Most features in Catel are async (such as vm initialization, etc). At first it might be a bit overwhelming, but once you get how it works, it's a very convenient way of programming. In the meantime, you can use a workaround (this is not best practice, but will get you through this task):
private async void Asd()
{
var b = await StartDialog(true);
}
Note that async void is not recommended and should really be avoided unless no other options are available (such as non-async event handlers, etc).
As a general practice, we have been injecting our own "service" classes to all our function apps, and we want to do the same thing for the Orchestrator.
Example:
public async Task<string> Run(
[OrchestrationTrigger] IDurableOrchestrationContext context,
ILogger log)
{
try
{
// get input
var input = context.GetInput<MyInputType>();
// do some stuff #1
var input1 = new BlahBlahOne();
await context.CallActivityWithRetryAsync<string>("activityfn1", retryOptions, input1);
// do some stuff #2
var input1 = new BlahBlahTwo();
await context.CallActivityWithRetryAsync<string>("activityfn3", retryOptions, input1);
// do some stuff #3
var input1 = new BlahBlahThree();
await context.CallActivityWithRetryAsync<string>("activityfn3", retryOptions, input1);
// do some stuff #4
return "I'm done";
}
catch (Exception ex)
{
log.LogError(ex, "unexpected error");
throw;
}
}
We'd like to do something like this:
public async Task<string> Run(
[OrchestrationTrigger] IDurableOrchestrationContext context,
ILogger log)
{
try
{
string output = await _myOrchestratorService.RunAsync(context); // NOT allowed!
return output
}
catch (Exception ex)
{
log.LogError(ex, "unexpected error");
throw;
}
}
However, Note that we can't use 'await' as per Durable Functions code constraints on multi-threading. So I tried below, but how do I code it? Calling .Result makes the code 'hang' on the Activity function. What am I doing wrong?
public string Run(IDurableOrchestrationContext context)
{
// code like before, but then how do I call this?
// await context.CallActivityWithRetryAsync<string>("activityfn1", retryOptions, input1);
// I tried this, doesn't work, will hang on the first activity function
context.CallActivityWithRetryAsync<string>("activityfn1", retryOptions, input1).Result;
}
To clarify, the restriction on the use of await in Orchestrator functions only applies to tasks that are not generated by IDurableOrchestrationContext APIs. To quote the Durable Functions orchestration code constraint documentation:
Orchestrator code must never start any async operation except by using the IDurableOrchestrationContext API or the context.df object's API. For example, you can't use Task.Run, Task.Delay, and HttpClient.SendAsync in .NET or setTimeout and setInterval in JavaScript. The Durable Task Framework runs orchestrator code on a single thread. It can't interact with any other threads that might be called by other async APIs.
As this answer shows, asynchronous helper methods that only call await on Task objects created by IDurableOrchestrationContext are technically safe to await on as well. That means that your call to await _myOrchestratorService.RunAsync(context); may be alright, as long as that asynchronous method follows all of the normal orchestration code constraints.
All of that being said, I am not entirely sure what you gain by injecting a service that appears to only have a single method that contains all of the logic that would normally live in your orchestration method. That abstraction doesn't appear to improve the testability of the code, and the extra layer of abstraction may confuse our Durable Functions analyzer that is helpful in diagnosing when your code violates orchestration constraints.
Just make it async Task<string>. It should work
public async Task<string> RunAsync(IDurableOrchestrationContext context)
{
var result = await context.CallActivityWithRetryAsync<string>("activityfn1", retryOptions, input1);
return result;
}
I have method in class MyClassB which is triggered asynchronously from a method of MyClassA:
public void getProductCall()
{
new Thread(new Runnable() {
#Override
public void run() {
try {
productRequest = service.createS4ProductRequest(getRepriceItems());
//Below is a rest call to another system
String response = pricing.getS4ProductResponse(quote.getAssetQuoteNrAndVrsn(), productRequest);
//I'm using the below 2 lines to check from ClassA's method to see if this process has ended
setProductResponse(response);
productPriceProcessEnded=true;
} catch (Exception e) {
productPriceErrorOccured=true;
e.printStackTrace();
}
}
}).start();
}
This is the piece of code in MyClassA i used to check if the above method is complete.
for(int i=0;i<1000000000;i++)
{
if(!networkAsynCalls.isListPriceErrorOccured())
{
if(networkAsynCalls.isListPriceprocessEnded())
{
return networkAsynCalls.getListReponse();
}
else
{
Thread.sleep(250);
continue;
}
}
else
return null;
}
instead of using this random for loop can i use some inbuilt method or service pool or something ?
Because,
1) This thread on method is in another class
2) In class MyClassB i have few more methods like this, so i need to check the status of all the methods in MyClassA
Thanks for any help.
If I undestand what you're trying to do is dispatch some code to be ran asynchronously, then be able to wait until it is completed (successfully or failed). If that's the case, you should take a look at Futures.
Here is an example based on the Javadoc:
FutureTask<String> future =
new FutureTask<String>(new Callable<String>() {
public String call() {
// do stuff
return "result";
}});
This code creates an object "future" that can be invoked to execute searcher.search(target). At this point, the code is not executed at all. You simply have an object representing a computation that may be executed asynchronously. To do so, you'd call:
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(future);
This snippet created an Executor (which is a fixed pool of 5 threads), then handed over the future to it for execution. The executor will run the computation from Future asynchronously.
Future offers some methods (see the Javadoc) to wait until completion, cancel, check completion status, etc. For example,
String result = future.get();
will block, waiting for the result indefinitely. A get(10, TimeUnit.SECONDS) will wait for 10 seconds and if the future has not completed, throw.
I have a problem with this code
if(Handlers.Count==0)
{
GetHandlers();
while (_handlers.Count == 0)
{
Thread.Sleep(100);
}
}
return _showroomLogs;
This method executes:
private void GetHandlers()
{
WebSerive.GetHandlersCompleted += new EventHandler<GetHandlersCompletedEventArgs>(OnGetHandlersCompleted);
WebSerive.GetHandlersAsync(_app.HandlerId);
}
but to this method:
private void OnGetHandlersCompleted(object sender, GetHandlersCompletedEventArgs e)
{
WebSerive.GetHandlersCompleted -= new EventHandler<GetHandlersCompletedEventArgs>(OnGetHandlersCompleted);
_handlers = e.Result;
}
I fall into afterd execution of
return _showroomLogs;
of cource if I remove this piece with While
What I must to do, to have executed OnGetHandlersAsync before
return _showroomLogs;
?
You need to recognise that as soon as you introduce an asynchronous operation to a sequence the whole sequence becomes asynchronous. Using blocking techniques like Sleep is 99.99999% the wrong choice.
Restructure as:-
private void GetHandlers(int handlerID, Action<IList<Handler>> returnResult)
{
EventHandler<GetHandlersCompletedEventArgs> eh = null;
eh = (s, args) =>
{
WebSerive.GetHandlersCompleted -= eh;
returnResult(args.Result);
};
WebSerive.GetHandlersCompleted += eh;
WebSerive.GetHandlersAsync(handerlID);
}
you then call with:-
GetHandlers(_app.HandlerId, handlers =>
{
_handlers = handlers;
// Do other stuff
});
Edit
Let me outline at a conceptual level what the fundemental problem is here. Lets say I have button click event, which calls FuncA. FuncA calls FuncB, FuncB calls FuncC.
click -> FuncA -> FuncB -> FuncC
This whole sequence is synchronous it might look like:-
void Button_Click(object sender, EventArgs e)
{
FuncA();
//Do other stuff
}
void FuncA()
{
var result = FuncB();
//Do stuff with result;
}
string FuncB()
{
return FuncC() + " World";
}
string FuncC()
{
return "Hello";
}
But now lets change FuncC into something that operates asynchronously. It returns immediately but its return value is not available until later, it calls a callback method when done that carries the result as parameter. The problem for FuncB is that it wants to return a value but can't until the async operation of FuncC has completed. Rather than have FuncB block the thread, we need to turn FuncB into an asynchronous operation in the same manner as FuncC. This whole process needs to bubble all the way to the event. It becomes:-
void Button_Click(object sender, EventArgs e)
{
FuncA(() =>
{
//Do other stuff after FuncA has completed
});
}
void FuncA(Action callback)
{
FuncB(result =>
{
//Do stuff with result
// then finally
callback();
});
}
void FuncB(Action<string> returnResult)
{
FuncC(result => returnResult(result + " World"));
}
void FuncC(Action<string> returnResult)
{
Dispatcher.BeginInvoke(() => returnResult("Hello"));
}
This pattern will do when there is only one actual asynchronous operation involved. Things start to get really funky when you have a series of actual async calls to make within the same operation. To avoid excessive callback nesting a little framework help is needed. I call mine the AsyncOperationService which you can read about here.