3

I try looking for tutorial on running a stored procedure async via EF, but didn't find good one.

I have the following function that call stored procedure async

  1. Is this code really async?
  2. My function is failing because of timeout, why does EF care about timeout when function is async?
  3. Can I tell EF to ignore timeout when using async functions?

This is my code:

public async Task GenerateQueueAsync()    
{
    await Task.Run(() => ((MyEntities)_context).GenerateQueue());
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Gooloosh
  • 131
  • 1
  • 11
  • 1
    That's not async, timeouts have to do with the actual DB operation, not whether you block waiting for it. If you get a timeout, you have a problem that needs fixing, not ignoring. What does `GenerateQueue` do? Why does it take so long you get a timeout? – Panagiotis Kanavos Jan 27 '20 at 11:23
  • 1
    Are you trying to create a blocking queue on top of a table? That's not a good idea. Simply to get a queue that doesn't harm scalability or cause deadlocks you'd need some very careful SQL coding. Adding an ORM on top only makes things a lot harder. Some databases like SQL Server offer real notifications *without* blocking, eg through [query notifications](https://learn.microsoft.com/en-us/sql/connect/ado-net/sql/query-notifications-sql-server?view=sql-server-ver15) but those require extra configuration – Panagiotis Kanavos Jan 27 '20 at 11:29
  • 1
    This is not async, so what is the rignt way to call stored procedure async via ef? – Gooloosh Jan 27 '20 at 12:58
  • 1
    The queu is generating a table with thousands of records that's are caculated from several tables with a lot of rules, when the queue is running at night the run time is 8 seconds, but when it's run in the middle of the day, when the tables are busy its can take almost 3 minutes, and then it's fails. I know how to increase timout, but I want to make it more effient . thanks! – Gooloosh Jan 27 '20 at 13:03
  • 1
    Don't use EF then, call the stored procedure directly with ADO.NET and set the command timeout to an appropriate value. EF is an Object-Relational Mapper. In this case though there are neither objects nor mapping involved – Panagiotis Kanavos Jan 27 '20 at 13:06
  • 1
    `async/await` helps avoid blocking the application's threads while waiting for an IO-bound operation to complete (like the database call). It doesn't affect that IO operation. – Panagiotis Kanavos Jan 27 '20 at 13:08
  • 1
    @Gooloosh As I have included in my answer, you need to use Bulk Operations properly for such scenario. Bulk Operations are available in Both TSQL and EF and also as Panagiotis Kanavos says you can also use ADO.NET. Thousands of records is nothing big for a bulk operation to handle! Also according to this answer https://stackoverflow.com/questions/28543293/entity-framework-async-operation-takes-ten-times-as-long-to-complete using async/await with EF is a very bad idea for performance optimization. – gwt Jan 27 '20 at 13:23

1 Answers1

2
  1. No it's not.

  2. It is the way EF is designed! One reason could be to prevent endless deadlocks. But as answered in number 3 you can modify the timeout.

  3. You can set the context CommandTimeout to 0 in Entity Framework to tell it to wait indefinitely. In order to set this value in different EF versions:

Entity Framework Core 2.0: The IDesignTimeDbContextFactory is introduced:

public class SampleContextFactory : IDesignTimeDbContextFactory<SampleContext>
{
    public SampleContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<SampleContext>();
        optionsBuilder.UseSqlServer(
            @"Server=.\;Database=db;Trusted_Connection=True;", 
            opts => opts.CommandTimeout(0)
            );

        return new SampleContext(optionsBuilder.Options);
    }
}

And you must ensure that your context has a constructor that takes a DbContextOptions object as a parameter:

public SampleContext(DbContextOptions options) : base(options) { }

Entity Framework Core 1.0:

context.Database.SetCommandTimeout(0);

Entity Framework 6:

context.Database.CommandTimeout = 0;

Note The existing capability offered by EF to modify the query execution timeout, does not mean that it should be done in all cases. The query execution timeout should be set as high as the successful execution of most queries could be guaranteed and also as low as the queries won't execute and waste or even in some cases lock the resources endlessly.

There are several things that you can do before increasing the timeout such as:

Query optimization:

Hosting machine software and hardware enhancement

Modifying your database tables to have proper indexing

In the end according to this answer using async/await with EF is a very bad idea for performance optimization.

gwt
  • 2,331
  • 4
  • 37
  • 59
  • 1
    I didn't ask how to increase the timeout, I want to understand if using async should solve the timeout problem? sorry I was not so clear before – Gooloosh Jan 27 '20 at 13:05
  • 1
    @Gooloosh I edited my answer please check it again. You can set the CommandTimeout to zero for it to execute indefinitely. – gwt Jan 27 '20 at 13:07
  • 1
    I marked this answer, because you answered my question, as I comment before, I need to know what's the rignt way to call stored procedure async via ef? – Gooloosh Jan 27 '20 at 13:28
  • 1
    @Gooloosh As I mentioned before it is a bad idea to use async with EF. You can call a SP from inside EF normally. But since EF is an ORM and loads data into memory be carefull not to load a lot of data into memory and try to use EF Bulk Library extensions instead. According to the question context and posted info I can not provide any more info. May be you could post another question explaining what you are trying to do in detail, providing your sp and ef code and ... then that could be answered. – gwt Jan 27 '20 at 13:34
  • 2
    I'm not trying to load a lot of data to memory, the procedurd only return true/false when finish successfully, I just want to run stored procedure (running on Sql server), and while sql server running, and the site is waiting it to finish,I want to free the thread for other.. why it's so bad? – Gooloosh Jan 27 '20 at 13:41
  • 1
    @Gooloosh For why async/await is bad, please refer to the link I provided at the end of my answer. As I mentioned, you need to post a new question and completely explain your scenario and also provide your current implementation with details, then according to your scenario and requirements, different optimization solutions and approaches could be suggested to you. – gwt Jan 27 '20 at 13:58
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/206723/discussion-between-gooloosh-and-karamafrooz). – Gooloosh Jan 27 '20 at 14:09