0

I have Blocking Collection of some lists and I process it in a task - add the data from blocking collection to database. Here is some part of the code:

private static Task _databaseTask;
private static readonly BlockingCollection<List<SomeItem>> DataToBeInsertedToDatabase = new BlockingCollection<List<SomeItem>>();
public static void ProcessInsertsCollection()
{
    _databaseTask = Task.Factory.StartNew(() =>
    {
        foreach (List<SomeItem> data in DataToBeInsertedToDatabase.GetConsumingEnumerable())
        {
            try
            {
                DateTime[] dateTimes = data.Select(d => d.ContributionDateTime).ToArray();
                string[] values = data.Select(d => d.Value).ToArray();
                string[] someOtherValues = data.Select(d => d.SomeOtherValues).ToArray();
                Program.IncrementDatabaseRecordsRegistered(data.Count);
                DatabaseClass.InsertValues(dateTimes, values, someOtherValues);
            }
            catch (Exception ex)
            {
                //log the error
            }
        }
    });
}

Function from DatabaseClass:

public static bool InsertValues(DateTime[] dateTimes, string[] values, string[] someOtherValues)
{
    if (!IsConnected())
    {
        Connect();
    }
    var rowsInserted = 0;
    try
    {
        using (OracleCommand command = _connection.CreateCommand())
        {
            command.CommandText =
                string.Format(
                    "Insert into {0} (*****) VALUES (:1, :2, :3)",
                    _tableName);
            command.Parameters.Add(new OracleParameter("1",
                OracleDbType.Date,
                dateTimes,
                ParameterDirection.Input));
            command.Parameters.Add(new OracleParameter("2",
                OracleDbType.Varchar2,
                values,
                ParameterDirection.Input));
            command.Parameters.Add(new OracleParameter("3",
                OracleDbType.Varchar2,
                someOtherValues,
                ParameterDirection.Input));

            command.ArrayBindCount = dateTimes.Length;
            rowsInserted = command.ExecuteNonQuery();
        }
    }
    catch (Exception ex)
    {
        //log the error
    }
    return rowsInserted != 0;
}

The problem is that after few hours of application working data are still being added to blocking collection but not processed. When I debug it then it does not stop at any breakpoint inside the task. When I check the variable _databaseTask it shows that task is running. The _connection variable shows that database is connected. I added try/catch to the foreach and also in the InsertValues function but it did not help. I made everything static because I firstly thought that this task was collected by GC. But it was not.

Probably the problem is connected with calling database because in my application I have another blocking collection and processing it in a task works without any problems. I do not call there any database function.

Could anyone please help me to find out why the collection is not consumed after few hours?

EDIT: Please do not vote down when you do not understand the question. You lower the possibility that someone who knows the solution sees my question. I did a lot of research on the problem.

Today I notice that probably the thread hangs on line rowsInserted = command.ExecuteNonQuery(); I will try to add the timeout there and also to add transaction.

msk
  • 32
  • 4
  • Where do you call ProcessInsertsCollection() ? s it not the case that the processinsertscollection taks stops running at some point due to no more inserts to be done and is not called again afterwards when new inserts are to be processed? – pijemcolu Jun 28 '16 at 12:50
  • I call it at the start of application. The may not be records to insert for some time but if processinsertscollection stops running then the task (_databaseTask ) should not shows that it is running when I debug the code. Am I right? – msk Jun 28 '16 at 13:12
  • If I was you, I would, remove try catch (you don't really want to silence any errors while in production / debugging ), put a breakpoint on entry point of that task and the exit point of that task. See when the task starts, when does it exit. After ProcessInsertCollection exits, do you have a way to restart the task? You claim the task is running. If it is running, which line is it? , by putting braekpoints on the start and exit lines you will find out. – pijemcolu Jun 28 '16 at 14:11
  • Previously i did not have try/catch but I add it to make sure that foreach loop is not broken because of some error. When the situation happens that blocking collection is not processed and I connect to debug it then I can see that this task is still runnnig. Only seems that foreach inside the task does not work as debugger does not stop at any breakpoint I set there. – msk Jun 28 '16 at 14:21
  • And inside the catch I log the error to the file. I just put there //log the error because I did not wanted to copy no necessary code for the problem. – msk Jun 28 '16 at 14:32
  • You keep saying that your task is running, Which line is running? Unless you can answer that, there's no hope. – pijemcolu Jun 28 '16 at 15:01
  • I think you do not understand me. I said I debug the code and read the varaiable __databaseTask_. It is variable of the class where the ProcessInsertCollection is. So I put breakpoint at function which adds data to collection and I check the status of the task (as databaseTask is a type _Task_) and the property _Status_ is _Running_. ProcessInsertCollection does not exit. Only the foreach inside in not running. – msk Jun 28 '16 at 16:30

1 Answers1

0

Afer difficult investigation I found the issue. I add the answer, maybe it will help someone.

The problem was with line rowsInserted = command.ExecuteNonQuery(); Default timeout for OracleCommand is 0 which enforces no time limit. As it was blocked by some other session it hangs forever. The solution was to add the timeout for the command by using CommandTimeout property of OracleCommand. And then implement the mechanism of retrying the insertion.

msk
  • 32
  • 4