Выполнить хранимую процедуру из окна формы асинхронно, а затем отключить?
Я вызываю хранимую процедуру из своего приложения, выполнение которой может занять 30 минут.
Я не хочу, чтобы мой пользователь оставлял приложение открытым в течение всего этого периода времени. Поэтому я хотел бы вызвать sproc, позволить ему летать, и позволить им закрыть приложение и вернуться позже.
Как я могу это сделать?
8 ответов
На самом деле это довольно распространенный сценарий. Вы не можете ничего сделать на основе клиента, потому что клиент может уйти и отключиться, и вы потеряете работу, проделанную до сих пор. Решением является использование Service Broker Activation: вы создаете сервис в базе данных и присоединяете активированную процедуру. В своем приложении (или странице ASP) вы отправляете сообщение в сервис и встраиваете необходимые параметры для вашей процедуры. После фиксации вашего приложения сообщение активирует сервисную процедуру. сервисная процедура считывает параметры из сообщения и вызывает вашу процедуру. поскольку активация происходит в потоке сервера, не связанном с вашим исходным соединением, это надежно. Фактически сервер может даже завершить работу и перезапуститься во время выполнения вашей процедуры, и работа будет откатана, а затем возобновлена, так как активирующее сообщение снова запустит сервисную процедуру после перезапуска.
Обновить
Я опубликовал подробную информацию о том, как это сделать, в том числе пример кода в моем блоге: Асинхронное выполнение процедуры.
Вы можете использовать BeginExecuteXXX
/EndExecuteXXX
методы (в зависимости от того, возвращает ли он результат или нет) SqlCommand
Передача делегата обратного вызова.
Я предлагаю ре-архитектуру. Создайте таблицу "Очередь работ", в которую вы записываете запросы на запуск хранимой процедуры. Затем либо предоставьте службу Windows или задание SQL Server, чтобы время от времени проверять рабочую очередь (или будьте очень изобретательны и используйте триггер), чтобы запустить хранимую процедуру. Попросите хранимую процедуру периодически обновлять ход выполнения в таблице рабочих очередей, и ваш интерфейсный пользователь может посмотреть на это, сообщить пользователю ход выполнения, а затем отобразить результаты, когда они будут выполнены.
Я предпочитаю использовать фоновый сервис для автономной обработки, когда ваше пользовательское приложение сообщает службе, что делать, а затем отключается. Служба может регистрировать истекшее время и ошибки / статус и перезапускаться при необходимости. WCF предназначен для этого и поддерживает очереди для связи.
Если вы действительно хотите полностью закрыть свое приложение, я предлагаю вам определить задание в агенте SQL Server и просто выполнить инструкцию T-SQL, чтобы запустить это задание вручную. Синтаксис:
sp_start_job
{ [@job_name =] 'job_name'
| [@job_id =] job_id }
[ , [@error_flag =] error_flag]
[ , [@server_name =] 'server_name']
[ , [@step_name =] 'step_name']
[ , [@output_flag =] output_flag]
Работа будет выполнять вашу хранимую процедуру. Вы должны будете быть немного творческими, чтобы передать любые аргументы. Например, вставьте параметры в таблицу "queue" и сделайте так, чтобы задание обрабатывало все строки в очереди.
Вместо задания также должен работать триггер вставки в вашей очереди.
Другой способ, который вы могли бы сделать, - позволить вашему приложению работать в фоновом режиме (возможно, в области уведомлений), а затем выйти или уведомить о завершении задания. Вы можете использовать это, используя методы BeginExecuteNonQuery и EndExecuteNonQuery, чтобы позволить ему работать в отдельном потоке.
пусть они закроют приложение и вернутся позже
Если вы хотите, чтобы они полностью закрыли приложение, вам нужно запустить отдельный.exe-файл или что-то в другом ThreadPool, который выполняет ваш код, вызывая хранимую процедуру. В противном случае ваша нить умрет, когда вы закроете приложение.
Главное окно вашего приложения не нужно открывать. Если вы запустили его как вторичный поток, он будет работать до тех пор, пока IsBackground == false
, Я обычно предпочитаю делать это через агента SQL Server или как клиент-серверное приложение (ничто не мешает клиент-серверному приложению работать на одном компьютере или даже быть одним и тем же двоичным файлом).
Прошло много времени...
using System.Threading;
.....
Thread _t = null;
void StartProcedure()
{
_t = new Thread(new ThreadStart(this.StartProc));
_t.IsBackground = false;//If I remember correctly, this is the default value.
_t.Start();
}
bool ProcedureIsRunning
{
get { return _t.IsRunning; } //Maybe it's IsActive. Can't remember.
}
void StartProc(object param)
{
//your logic here.. could also do this as an anonymous method. Broke it out to keep it simple.
}