У меня есть таблица, которая действует как очередь сообщений. Сообщение обрабатывается, если 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# о том, что асинхронная задача завершена, и выполняется до тех пор, пока все не будет завершено.
Да, он очищается несколькими службами Multi Thread Wrapper (с 15 процессами)
Как насчет этого? Следите за изменениями Oracle Database в .net
Эта часть будет сосредоточена на прослушивании БД Oracle и последующем запуске действия. Если я буду слушать в середине своих строк кода, событие может быть вызвано позже. Хотя это дало мне идею, хотя я не уверен, что это то, что мы можем сделать. Пожалуйста, смотрите отредактированную версию для этого.
Любое событие можно преобразовать в асинхронный метод, используя TaskCompletionSource
. Пример можно посмотреть здесь . Если вы используете .NET 5, был введен неуниверсальный класс TaskCompletionSource, поэтому нет необходимости в одноразовом типе, как в примере.
Правда, хотя я бы не знал, как указать задачу завершения, например. Он будет срабатывать каждый раз, когда обновляется строка, но я бы хотел, чтобы он срабатывал только после обновления всех строк. Это усложняет вещи, я считаю....
Я мало что знаю об Oracle, но ожидаю, что должна быть возможность запрашивать уведомления о конкретном событии, например, когда конкретный SQL-запрос возвращает хотя бы одну запись или определенное значение. Но я могу ошибаться. Если это невозможно, вы можете сделать это вручную с помощью триггеров. Вы можете добавить триггер DELETE
в таблицу v_mq
и убедиться, что при удалении последней строки строка добавляется в другую таблицу с именем, например Push_Notifications
, и прикрепить механизм уведомления к этой таблице.
Боже! Это было бы идеально! Мне просто нужно выяснить, как на самом деле это сделать!
Я надеюсь, что вам это действительно нужно, потому что это кажется сложным для реализации, настройки, развертывания и обслуживания и, вероятно, увеличит SPOF (единичные точки отказа) вашего приложения!
Это для целей тестирования, а не само приложение. понять, как экономить время до последней секунды.
Другая идея, основанная на вашем первоначальном подходе к извлечению, состоит в том, чтобы настроить скорость/темп извлечения на основе существующего количества записей. Тяните медленно, пока записей много, ускоряйтесь, когда записей мало.
Вместо «Thread.Sleep()» используйте «await Task.Delay()», который не блокирует.
Я ищу решение, которое вообще не предполагает ожидания.
А пока я пойду по течению, как в последнем комментарии:
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);
}
}
Как очищается стол? Обрабатывается ли он одновременно другим потоком или процессом?