Асинхронные события в СУБД

добавлено: 20 янв 16
понравилось:0
просмотров: 1684
комментов: 1

теги:

Автор: Old Nick

Для начала прочитайте статью про события в СУБД
Данная статься является продолжением-дополнением к статье про обычные события.

Для чего они вообще нужны, асинхронные события?
Иногда какая либо логика может быть очень весомой и отнимать немалые ресурсы и обрабатывать ее синхронно невыгодно, можно повесить сервер или заблокировать таблицу. Вот в таком случае выгодно вынести обработку в отдельный поток, который может даже обрабатывать такие события в часы и минуты простоя. То есть вы провели документы по складу, но при этом накладная на выдачу сформировалась не сразу, а легла в очередь, через 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


Всё, наслаждайтесь асинхронной обработкой событий.

Комментарии


  • Почему бы не использовать встроенные механизм Service Broker, он как раз создан для асинхронных вызовов?
    1. Триггером ставим в очередь.
    2. Пришем процедуру обработки для приемника.
    3. Активируем очередь приемника выполнением той процедурой указав кол-во обрабатываемых потоков. Если надо распаралелить.
    4. радуемся.
    Используется достаточно просто:
    1. триггер отправляет сообщение в очередь.
    2. сервис брокер видит входящее сообщение сообщение и активирует процедуру.
    3. процедура делает полезные вещи по факту события и не надо делать джобы.



Необходимо войти на сайт, чтобы оставлять комментарии