Как я могу дождаться, когда таблица пуста/обработана очередь сообщений?

У меня есть таблица, которая действует как очередь сообщений. Сообщение обрабатывается, если search_flag is Null. В настоящее время я использую метод ниже, чтобы проверить, пуста ли таблица (в данном случае представление этой таблицы). Если он пуст, я бы хотел продолжить обработку данных.

public async static void CheckMessageQueue(int waitTime = 1)
{
    var count = 1;
    var loop = 0;
    using var oracleConnection = GetOracleConnection();
    while (count > 0)
    {
        Thread.Sleep(waitTime * 1500);
        const string sqlSelect = "select count(*) from v_mq";

        var dr = await GetDataRead(sqlSelect, oracleConnection);

        while (dr.Read())
            count = int.Parse(dr.GetValue(0).ToString() ?? string.Empty);

        loop++;
        if (loop > 50)
            break;
    }
}

И метод GetDataRead.

static async Task<OracleDataReader> GetDataRead(string sqlQuery, OracleConnection oracleConnection)
{
    var cmd = new OracleCommand(sqlQuery, oracleConnection) { CommandType = CommandType.Text };
    var dr = await cmd.ExecuteReaderAsync();
    return (OracleDataReader)dr;
}

Приведенный выше код работает, хотя у меня проблема в том, что я Sleeping и жду статического времени, я бы хотел перейти к следующей задаче, как только она все обработает сразу.

Так что я хотел бы иметь что-то вроде await CheckMessageQueue().

Если я использую описанный выше подход без сна, не станет ли это тяжелым бременем для системы?

Одной из идей было бы постоянно запрашивать базу данных, как показано ниже. Хотя я боюсь, что это может привести к нестабильности производительности.

public async static void CheckMessageQueue(int waitTime = 1)
{
    var count = 1;
    var loop = 0;
    using var oracleConnection = GetOracleConnection();
    while (count > 0)
    {           
        const string sqlSelect = "select count(*) from v_mq";
        var dr = await GetDataRead(sqlSelect, oracleConnection);
        while (dr.Read())
            count = int.Parse(dr.GetValue(0).ToString() ?? string.Empty);      
    }
}

Может ли кто-нибудь предложить лучший способ, как справиться с этим?

ОБНОВЛЯТЬ: У меня не может быть события для прослушивания таблицы, если я не могу ждать, пока событие не будет выполнено.

Хотя есть ли возможность создать в PL_SQL триггер/ограничение, которое заставило бы соединение C# ждать до тех пор, пока не будет выполнен указанный процесс?

На стороне С#:

ожидание очистки таблицы();

// Продолжайте выполнять только задачи. После того, как TableIsCLeared, search_flag помечен как Null.

В Oracle (сторона PL_SQL)

Каким-то образом уведомить код C# о том, что асинхронная задача завершена, и выполняется до тех пор, пока все не будет завершено.

Как очищается стол? Обрабатывается ли он одновременно другим потоком или процессом?

Theodor Zoulias 15.12.2020 16:18

Да, он очищается несколькими службами Multi Thread Wrapper (с 15 процессами)

YoungDad 15.12.2020 17:51

Как насчет этого? Следите за изменениями Oracle Database в .net

Theodor Zoulias 15.12.2020 18:10

Эта часть будет сосредоточена на прослушивании БД Oracle и последующем запуске действия. Если я буду слушать в середине своих строк кода, событие может быть вызвано позже. Хотя это дало мне идею, хотя я не уверен, что это то, что мы можем сделать. Пожалуйста, смотрите отредактированную версию для этого.

YoungDad 16.12.2020 07:14

Любое событие можно преобразовать в асинхронный метод, используя TaskCompletionSource. Пример можно посмотреть здесь . Если вы используете .NET 5, был введен неуниверсальный класс TaskCompletionSource, поэтому нет необходимости в одноразовом типе, как в примере.

Theodor Zoulias 16.12.2020 07:33

Правда, хотя я бы не знал, как указать задачу завершения, например. Он будет срабатывать каждый раз, когда обновляется строка, но я бы хотел, чтобы он срабатывал только после обновления всех строк. Это усложняет вещи, я считаю....

YoungDad 16.12.2020 08:15

Я мало что знаю об Oracle, но ожидаю, что должна быть возможность запрашивать уведомления о конкретном событии, например, когда конкретный SQL-запрос возвращает хотя бы одну запись или определенное значение. Но я могу ошибаться. Если это невозможно, вы можете сделать это вручную с помощью триггеров. Вы можете добавить триггер DELETE в таблицу v_mq и убедиться, что при удалении последней строки строка добавляется в другую таблицу с именем, например Push_Notifications, и прикрепить механизм уведомления к этой таблице.

Theodor Zoulias 16.12.2020 08:24

Боже! Это было бы идеально! Мне просто нужно выяснить, как на самом деле это сделать!

YoungDad 16.12.2020 08:38

Я надеюсь, что вам это действительно нужно, потому что это кажется сложным для реализации, настройки, развертывания и обслуживания и, вероятно, увеличит SPOF (единичные точки отказа) вашего приложения!

Theodor Zoulias 16.12.2020 08:44

Это для целей тестирования, а не само приложение. понять, как экономить время до последней секунды.

YoungDad 16.12.2020 08:52

Другая идея, основанная на вашем первоначальном подходе к извлечению, состоит в том, чтобы настроить скорость/темп извлечения на основе существующего количества записей. Тяните медленно, пока записей много, ускоряйтесь, когда записей мало.

Theodor Zoulias 16.12.2020 08:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
11
233
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вместо «Thread.Sleep()» используйте «await Task.Delay()», который не блокирует.

Я ищу решение, которое вообще не предполагает ожидания.

YoungDad 15.12.2020 17:52
Ответ принят как подходящий

А пока я пойду по течению, как в последнем комментарии:

public static void CheckMessageQueue(int waitTime = 1)
{
    var count = 1;
    var start = DateTime.Now;
    using var oracleConnection = GetOracleConnection();
    while (count > 0 && DateTime.Now.Subtract(start).Minutes < 2)
    {
        if (count > 50)
        {
           Thread.Sleep(count * 100);
        }
        else
        {
            Thread.Sleep(250);
        }

        const string sqlSelect = "select count(*) from msg_queue where search_flag='Y'";
        var dr = GetDataRead(sqlSelect, oracleConnection);

        while (dr.Read())
            count = int.Parse(dr.GetValue(0).ToString() ?? string.Empty);
    }
}

Другие вопросы по теме