0

In the previous day I am looking for a way to make my code fully asynchronous. So that when called by a rest API, I' ll get an immediate response meanwhile the process is running in the background.

To do that I simply used tasks.Add(Task<bool>.Run( () => WholeProcessFunc(parameter) )) where WholeProcessFunc is the function that make all the calculations(it may be computationally intensive). It works as expected however I read that it is not optimal to wrap the whole process in a Task.Run.

My code need to compute different entity framework query which result depends on the previous one and contains also foreach loop. For instance I can' t understand which is the best practice to make async a function like this:

public async Task<List<float>> func()
{
    List<float> acsi = new List<float>();

    using (var db = new EFContext())
    {
        long[] ids = await db.table1.Join(db.table2 /*,...*/)
            .Where(/*...*/)
            .Select(/*...*/).ToArrayAsync();

        foreach (long id in ids)
        {
            var all = db.table1.Join(/*...*/)
                .Where(/*...*/);
            float acsi_temp = await all.OrderByDescending(/*...*/)
                .Select(/*...*/).FirstAsync();
            if (acsi_temp < 0) { break; }

            acsi.Add(acsi_temp);
        }
    }
    return acsi;
}

In particular I have difficulties with the foreach loop and the fact that the result of a query is used in the next . Finally with the break statement which I don't get how to translate it. I read about cancellation token, could it be the way ?

Is wrapping up all this function in a Task.Run a solid solution ?

5
  • Is wrapping up all this function in a Task.Run a solid solution ? No, web service applications shouldn't execute fire & forget processes. Use Hangfire, or an other tool/architecture that allows offloading these processes. Commented Jul 10, 2022 at 12:12
  • 1
    It is exceedingly difficult to reason about your program with all of the syntax errors you've added to it. Can you please post a version that we can copy, paste, and run? Then we can refactor it to show you how it is done. Commented Jul 12, 2022 at 3:05
  • What is the type of your application? Is it a Web API? ASP.NET? WinForms? Commented Jul 12, 2022 at 5:55
  • Thanks you all for the enlighning answers. I am running azure functions in .NET. I understand that asyncronize this piece of code is not a good way to achieve my goal. I did not add all the query cause is very complex and I am trying in parallel to optimize it, maybe running only one query avoiding the loop. Commented Jul 12, 2022 at 8:25
  • @DanieleMellino - Please don't add your actual query, but make a small sample that demonstrates what you're trying to do. We can then show you how to write your code with your sample. Commented Jul 12, 2022 at 8:58

2 Answers 2

1

In the previous day I am looking for a way to make my code fully asynchronous. So that when called by a rest api, I' ll get an immediate response meanwhile the process is running in the background.

Well, that's one meaning of the word "asynchronous". Unfortunately, it's completely different than the kind of "asynchronous" that async/await does. async yields to the thread pool, not the client (browser).

It works as expected however I read that it is not optimal to wrap the whole process in a Task.Run.

It only seems to work as expected. It's likely that once your web site gets higher load, it will start to fail. It's definite that once your web site gets busier and you do things like rolling upgrades, it will start to fail.

Is wrapping up all this function in a Task.Run a solid solution ?

Not at all. Fire-and-forget is inherently dangerous.

A proper solution should be a basic distributed architecture:

  • A durable queue, such as an Azure Queue or Rabbit (if properly configured to be durable).
  • An independent processor, such as an Azure Function or Win32 Service.

Then the ASP.NET app will encode the work to be done into a queue message, enqueue that to the durable queue, and then return. Some time later, the processor will retrieve the message from that queue and do the actual work.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. I' ll try to implement something like this learn.microsoft.com/en-us/azure/architecture/patterns/….
0

You can translate your code to return an IAsyncEnumerable<...>, that way the caller can process the results as they are obtained. In an asp.net 5 MVC endpoint, this includes writing serialised json to the browser;

public async IAsyncEnumerable<float> func()
{
    using (var db = new EFContext())
    {
        //...

        foreach (long id in ids)
        {
            //...
            if(acsi_temp<0) { yield break; }

            yield return acsi_temp;
        }
    }
}

public async Task<IActionResult> ControllerAction(){
    if (...)
        return NotFound();
    return Ok(func());
}

Note that if your endpoint is an async IAsyncEnumerable coroutine. In asp.net 5, your headers would be flushed before your action even started. Giving you no way to return any http error codes.

Though for performance, you should try rework your queries so you can fetch all the data up front.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.