-1

I have a windows forms app that works well on my development machine. However, I see strange behavior trying to run multiple tasks in parallel after publishing the application. There is no error, but it doesn't work as expected. Here is the code:

private async void Button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    try
    {
        var watch = Stopwatch.StartNew();
        textBox1.Text = $"Processing...";

        await SyncAppDbAsync();

        watch.Stop();
        var time = watch.ElapsedMilliseconds;
        textBox1.Text = $"End successfully. Minutes: {String.Format("{0:0.00}", (double)(time / 1000) / 60)}";
    }
    catch (Exception ex)
    {
        textBox1.Text = $"Message: {ex.Message}, Source: {ex.Source}, HResult: {ex.InnerException}";
    }

}

public async Task SyncAppDbAsync()
{
    //delete tables rows
    // I block the UI for some seconds because not want to write
    // a record if is not deleted
    Task.WaitAll(
        AgenteApp.RemoveAllAgentiAppAsync(),
        RubricaApp.RemoveAllRubricheAppAsync(),
       ...
    );

    //read data da from database
    var readAgents = Task.Run(Agent.GetAgentAsync);
    var readAddressBooks = Task.Run(AddressBook.GetAddressBookAsync);
    ...

    await Task.WhenAll(
         readAgents,
         readAddressBooks,
         ...
     );

    //save data on sqlite database(myDb.db)
    var addAgenti = Task.Run(async () =>
    {
        var progrIndicator = new Progress<int>(AgentiProgress);
        var agenti = AgenteApp.FillAgentiAppFromCompanyAsync(await readAgents, progrIndicator);
        await AgenteApp.AddAgentiAppAsync(await agenti);
    });
    var addRubriche = Task.Run(async () =>
    {
        var progrIndicator = new Progress<int>(RubricheProgress);
        var rubriche = RubricaApp.FillRubricheAppFromCompanyAsync(await readAddressBooks, progrIndicator);
        await RubricaApp.AddRubricheAppAsync(await rubriche);
    });


    await Task.WhenAll(
      addAgenti,
      addRubriche,
     ...
    );
}

Each task in that code corresponds to a table in an sqlite database. The code reads data from one sqlite database and writes to another sqlite database.

I expect this code to take a few minutes to run. In the meantime, there is a progress bar for each table that should update. Instead, the code runs in just a few seconds, the progress bars never update, and the database tables are unchanged. I see this text in my textbox at the end: End successfully. Minutes: 0,02.

What can I do to understand the problem and fix it? Again, this works correctly on my development machine.

UPDATE: Sorry to everyone: code works perfectly fine! I make stupid mistake with a path of sqlite database. I hardcoded in app.config:

I accept suggests on how make dynamic that path So again sorry

herosuper
  • 164
  • 1
  • 9
  • The `WaitAll` call blocks the thread and is not good for async. Try `WhenAll` instead. See https://stackoverflow.com/questions/6123406/waitall-vs-whenall – chue x Sep 23 '19 at 14:06
  • 6
    `There is no error`. That's fine... but in that situation you have to describe behavior to us. How could we possibly help debug this if you don't share what the observed behavior is, and how it differs from what was expected? – Joel Coehoorn Sep 23 '19 at 14:06
  • 1
    [In order for a question to be answered, it must specify what exactly is wrong. Stating simply that “it doesn’t work” is not sufficient.](http://idownvotedbecau.se/itsnotworking/) – Liam Sep 23 '19 at 14:09
  • It's not clear from your code, but interacting with a database is not inherently thread safe. For instance, using entity framework will have issues unless you specifically address multi threading. – BurnsBA Sep 23 '19 at 14:10
  • Thats an issue in EF not DBs @BurnsBA . Most ORMs are fine in a threaded environment and pretty much all DBs are thread safe, in fact that's pretty much the point of using a DB – Liam Sep 23 '19 at 14:12
  • I update now the behavior – herosuper Sep 23 '19 at 14:15
  • @herosuper - you have to describe 2 things: 1) what is supposed to happen, and 2) what currently is happening. You have the second thing, but not the first. – chue x Sep 23 '19 at 14:17
  • On the production environment, where is located the SQLite db file? From the [documentation](https://www.sqlite.org/lockingv3.html): ❝Your best defense is to not use SQLite for files on a network filesystem.❞ – Theodor Zoulias Sep 23 '19 at 15:12
  • I need to switch the path from environment: if i serilize c:\mySerializePath, instead if i deserialize i need c:\mydeserializePath – herosuper Sep 23 '19 at 15:21
  • i update my post – herosuper Oct 15 '19 at 15:28

1 Answers1

1

There's not enough information in the question at the time I'm writing this for me to evaluate the problem. But I can at least give some strategies that will help you find a solution on your own:

  1. Add excessive and detailed logging to the code (You can remove it later). That will help you understand what is happening as the program runs, and potentially see where it goes wrong. Run this in production if you have to, but preferably:

  2. If you don't already have one, get a staging or QA environment separate from your own machine, (use a local VM if you really have to) where you can reproduce the problem on demand, away from production. The logging information from the previous step may help with this.

  3. Look for exceptions that might be hidden by the async code. Make sure you're checking the result of each of those operations.

  4. Remove most of the code. The program will be incomplete, but it will run that incomplete section as expected. Keep adding more small chunks of the complete program back until it breaks again. At this point, you will (probably) know where the issue is... though it could be a race condition caused by an earlier block, but at least you'll have a clue where to start looking.

  5. Unroll the async code and run everything using traditional synchronized methods. Make sure the simple synchronized code works in the production environment before trying to adding parallelism.

When you finally track down this issue, make sure you have a unit test that will detect the problem in the future before it goes to production, to avoid a regression.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794