Асинхронные события в СУБД
Для начала прочитайте статью про события в СУБД
Данная статься является продолжением-дополнением к статье про обычные события.
Для чего они вообще нужны, асинхронные события?
Иногда какая либо логика может быть очень весомой и отнимать немалые ресурсы и обрабатывать ее синхронно невыгодно, можно повесить сервер или заблокировать таблицу. Вот в таком случае выгодно вынести обработку в отдельный поток, который может даже обрабатывать такие события в часы и минуты простоя. То есть вы провели документы по складу, но при этом накладная на выдачу сформировалась не сразу, а легла в очередь, через 1-2 минуты она появится у кладовщика.
Для реализации асинхронного события нужно создать таблицу для хранения очереди возникших событий и асинхронный обработчик, который будет работать в отдельном потоке, для чего подойдет JOB.
Создадим таблицу
EventOID - идентификатор события
RaiseTime - время добавления события в очередь
StartTime - время возникновения (возбуждения) события. То есть событие попало в очередь сегодня, а обработаться должно будет через 2 дня.
SenderOID - идентификатор объекта, бросившего событие
Следующие три поля нужны в случае возникновения ошибки при обработке
Теперь нужно написать хранимую процедуру, которая возбуждает событие
И еще нужна хранимая процедура для обработки асинхронных событий
Ну и собственно нужно написать скрипт для JOB'а
Всё, наслаждайтесь асинхронной обработкой событий.
Данная статься является продолжением-дополнением к статье про обычные события.
Для чего они вообще нужны, асинхронные события?
Иногда какая либо логика может быть очень весомой и отнимать немалые ресурсы и обрабатывать ее синхронно невыгодно, можно повесить сервер или заблокировать таблицу. Вот в таком случае выгодно вынести обработку в отдельный поток, который может даже обрабатывать такие события в часы и минуты простоя. То есть вы провели документы по складу, но при этом накладная на выдачу сформировалась не сразу, а легла в очередь, через 1-2 минуты она появится у кладовщика.
Для реализации асинхронного события нужно создать таблицу для хранения очереди возникших событий и асинхронный обработчик, который будет работать в отдельном потоке, для чего подойдет JOB.
Создадим таблицу
create table Queue ( ID int identity(1, 1), EventOID int, RaiseTime datetime, StartTime datetime, SenderOID int, Error bit, ErrorMsg varchar(1024), TryCount int default 0, primary key (ID ) ) go create index IX_Total on Queue ( StartTime, RaiseTime, EventOID ) go
EventOID - идентификатор события
RaiseTime - время добавления события в очередь
StartTime - время возникновения (возбуждения) события. То есть событие попало в очередь сегодня, а обработаться должно будет через 2 дня.
SenderOID - идентификатор объекта, бросившего событие
Следующие три поля нужны в случае возникновения ошибки при обработке
Теперь нужно написать хранимую процедуру, которая возбуждает событие
create procedure Event_OnCreate_ThrowAsync @SenderOID int -- идентификатор объекта, который бросает событие @StartTime datetime = getdate() as declare @EventOID int select @EventOID = OID from VEvent where Name = 'Create' insert into Queue ( EventOID, RaiseTime, StartTime ) values ( @EventOID, getdate(), @StartTime ) go
И еще нужна хранимая процедура для обработки асинхронных событий
create procedure HandleEventsAsync as declare @EventOID int, @TryCount int, @SenderOID int, @ID int select top 1 @EventOID = EventOID, @TryCount = TryCount, @SenderOID = SenderOID, @ID = ID from Events where StartTime <= getdate() and (Error = 0 or TryCount <=3) order by RaiseTime declare Cur cursor fast_forward for select h.ProcName from TEvent_Handlers h where h.OID = @EventOID and h.Async = 1 open Cur fetch next from Cur into @ProcName while @@fetch_status = 0 begin begin try exec @ProcName @SenderOID delete Queue where ID = @ID end try begin catch set @ErrorMsg = 'Ошибка при обработке события, процедура: "' + isnull(@ProcName, 'процедура не найдена') + '" (ERROR_PROCEDURE ' + isnull(ERROR_PROCEDURE(), '') + ', Line ' + isnull(cast(ERROR_LINE() as varchar), '') + '), ' + isnull(ERROR_MESSAGE(), '') if @TryCount < 3 update Queue set TryCount = @TryCount + 1, Error = 1 where ID = @ID else update Queue set Error = 1, ErrorMsg = @ErrorMsg where ID = @ID end catch fetch next from Cur into @ProcName end close Cur deallocate Cur go
Ну и собственно нужно написать скрипт для JOB'а
while 1 = 1 begin exec HandleEventsAsync wait for delay '00:00:00.001' end
Всё, наслаждайтесь асинхронной обработкой событий.