0

I'm working on a Blazor application.
When a user fills in a form the data needs to be saved to a table and a longer task needs to be run.
The user doesn't need to wait for this longer task to be completed. He will be notified later.
But when the long task is finished the table entry needs to be updated.
How to do this?

This is my current code which blocks to user until all is finished:

        public async Task<Client> Create(Client client)
        {
            client.DatabaseCreated = false;

            await _context.Clients.AddAsync(client);
            await _context.SaveChangesAsync();
            Debug.WriteLine("Client added");

            // Run longer task.
            try
            {
                // TODO: Don't wait for it:
                var longTask= myLongTask(client.Code, client.Id);
                // update table entry
                client.DatabaseCreated = true;
                var updateClient = _context.SaveChangesAsync();
                await Task.WhenAll(longTask, updateClient);
                Debug.WriteLine("Client updated");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }

            Debug.WriteLine("Client returned");
            return client;
        }
Paul Meems
  • 3,002
  • 4
  • 35
  • 66
  • 3
    Use `Task.Run` to start a task on a thread-pool-thread and forget about the returned task in the `create` method. But be aware of the livetime of the `_context`. The delegate passed to `Task.Run` should create its on db-context. – Ackdari Jul 27 '20 at 12:38
  • @Ackdari Agree. And to create `dbcontext` you can refer https://stackoverflow.com/a/48368934/9695286 & https://stackoverflow.com/a/39126718/9695286 – Karan Jul 27 '20 at 12:39
  • 5
    Fire-and-forget in ASP.NET is a bit tricky - make sure you understand the risks involved. See, for example, https://github.com/StephenCleary/AspNetBackgroundTasks – Heinzi Jul 27 '20 at 12:40
  • https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio – Johnathan Barclay Jul 27 '20 at 13:06
  • @Heinzi That GitHub is hardly relevant in ASP.NET Core - System.Web.* doesn't exist anymore – Camilo Terevinto Jul 27 '20 at 13:06
  • Hangfire is great for fire and forget. Check it out: https://www.hangfire.io/ – Ben D Jul 27 '20 at 13:13
  • 1
    @CamiloTerevinto: Even though the solution might differ, the problem (no guarantee that the background task completes) is the same in ASP.NET Core, or is it not? – Heinzi Jul 27 '20 at 14:10

1 Answers1

4

The user doesn't need to wait for this longer task to be completed. He will be notified later. How to do this?

To do this in a reliable way, you would need to 1) have a reliable queue (e.g., Azure Queue / Amazon SQS / etc.), and 2) have a background service (e.g., ASP.NET Core Background Service / Azure Function / Amazon Lambda / etc.). The ASP.NET API would just place a message onto the queue and then return; the background service reads from the queue and processes the messages.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thanks for the reply and sorry for the confusion. I know how to notify the user later, that part is already working. I need to know how to run the long task and update the database without letting the user wait. In other comments people are suggesting to use Task.Run and create the dbContext manually. I'll try that first. – Paul Meems Jul 28 '20 at 06:57
  • 1
    @PaulMeems: The problem with the Task.Run approach is that (a) it will work when you "try it" but (b) it will occasionally silently fail in production (for example, if the application pool is recycled at an inconvenient time). If that's acceptable for you, go for it, if it isn't, you'll need a more reliable solution. – Heinzi Jul 28 '20 at 08:50
  • Reading all comments and the links to relevant posts I've changed my mind. Since I need to create WebJobs later as well I'm going to create a webjob to execute my long-running task. Most likely this will raise new questions, like how to use DI with the static entry points of the webjobs. If I get stuck I'll post them as new questions. Thanks for your insights. – Paul Meems Jul 28 '20 at 09:14
  • This is not only reliable but also faster when you scale publishers and consumers horizontally. I encountered the same situation and i resolved it through the way via bus – Lapenkov Vladimir Oct 09 '21 at 17:48