Discarding an async method that itself awaits a command.ExecuteNonQueryAsync behaves as awaited

Mattias1335 1 Reputation point
2022-10-06T10:09:07.897+00:00

I posted this on stackoverflow as well (https://stackoverflow.com/questions/73948675/why-does-discarding-an-entityframework-firstordefaultasync-query-or-even-a-ora). But no one seems to have an answer for this other than "that should not be happening". Background is that I wanted to call "LONG_RUNNING_BACKGROUND_PROC" in our database without the client having to wait for its completion (it's a VERY long running background task and the client doesn't really need the result in that instance anyway).

But I immediatly noticed that _ = DbCallTestCommand() instead behaved as if I had awaited it instead of
becoming fire and forget like what usually happens if you use the discard.

This is the code that shows this behaviour:

    async Task Main()  
    {  
     "Main start!".Dump();  
      
     _ = DbCallTestCommand();  
      
     "Main Done!".Dump();  
    }  
      
    async Task DbCallTestCommand()  
    {  
     await using var connection = new OracleConnection(this.connectString);  
     await connection.OpenAsync();  
      
     await using var oracleCommand = new OracleCommand("", connection);  
     oracleCommand.CommandText = "LONG_RUNNING_BACKGROUND_PROC"; //<- long running statistic calculation job that the client shouldn't need to wait for.  
     oracleCommand.CommandType = CommandType.StoredProcedure;  

     await oracleCommand.ExecuteNonQueryAsync();  
      
     "DbCallTestCommand done".Dump();  
    }  
      
    async Task TaskDelayTest()  
    {  
     await Task.Delay(10000);  
      
     "TaskDelayTest done!".Dump();  
    }  
  

If one instead swap _ = DbCallTestCommand() with _ = TaskDelayTest() then it behaves as expected. So does anyone know how awaiting command.ExecuteNonQueryAsync is somehow able to alter the the behavour of the task/discard?

The only theory I have is that for some reason the task isn't really returned until ExecuteNonQueryAsync has finished it's processing. But I don't currently know of a way to confirm this.

I can fix this by using _ = Task.Run(() => DbCallTestCommand()) but that seems kinda wastefull, having to use 2 tasks instead of 1 when I'm not even interested in the result to begin with.

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,223 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Mattias1335 1 Reputation point
    2022-11-17T09:37:23.297+00:00

    After seeing a comment on a tweet about the upcoming ODP.NET 7 release. Where they were asking about if this release will finally come with "true async". I started doing some digging.

    As it turns out. No async method in OracleCommand is truly async. They're apparently fake. Which I'm guessing is the most likely reason why "fire and forget" using the _ discard operator simply doesn't work with OracleCommand executes.

    True async is however something that will be added in another ODP.NET release version, due sometime in 2023. See: https://github.com/oracle/dotnet-db-samples/issues/144 for more info.

    0 comments No comments