ModuleAsyncHandlers.cs 8.54 KB
using System;
using System.Collections.Generic;
using System.Linq;
using Sungero.Core;
using Sungero.CoreEntities;

namespace DirRX.Container.Server
{
  public class ModuleAsyncHandlers
  {

    public virtual void EnqueueDocumentForInventory(DirRX.Container.Server.AsyncHandlerInvokeArgs.EnqueueDocumentForInventoryInvokeArgs args)
    {
    }

    public virtual void ProcessNextStageForInventory(DirRX.Container.Server.AsyncHandlerInvokeArgs.ProcessNextStageForInventoryInvokeArgs args)
    {
      args.Retry = false;
      const int MaxRetryIteration = Constants.Module.ProcessingRequestMaxCount;
      
      // Заблокировать журнал на время обработки.
      var eventLog = Container.TransferEventLogs.Get(args.eventLogId);
      var status = eventLog.CurrentState;
      Logger.DebugFormat("Старт обработчика ProcessNextStageForInventory. ИД {0}. Статус: {1}", args.eventLogId, status.ToString());
      
      if (status == Container.TransferEventLog.CurrentState.Error || status == Container.TransferEventLog.CurrentState.Complete)
      {
        return;
      }
            
      if (Locks.TryLock(eventLog))
      {
        // Выполнить функцию обработки.
        var error = string.Empty;
        try
        {
          var moduleName = "DirRX.Container";
          var functionName = "ProcessArchiveDocument";
          if (eventLog.SelectionRule != null && !string.IsNullOrEmpty(eventLog.SelectionRule.ProcessingFunction))
            functionName = eventLog.SelectionRule.ProcessingFunction;
          
          var result = (DirRX.Container.ITransferEventLog)Functions.Module.ExecuteServerFunction(moduleName, functionName, new object[] { eventLog });
          // Если статус не изменился, попытаться еще раз выполнить эту стадию.
          if (result.CurrentState == status)
          {            
            if (args.RetryIteration <= MaxRetryIteration)
            {
              args.Retry = true;
              args.NextRetryTime = Calendar.Now.AddMinutes(5);
              Logger.DebugFormat("ProcessNextStageForInventory. Ожидание повторной обработки ИД {0}. Итерация: {1}", args.eventLogId, args.RetryIteration);
            }
            else
            {
              error = "Превышено максимальное число попыток обработки";
            }
          }
        }
        catch (Exception ex)
        {
          error = Resources.ErrorProcessingFunctionFormat(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
          Logger.DebugFormat("ProcessArchiveDocument. Обработка документа ИД {0}. Ошибка: {1}", args.eventLogId, ex.StackTrace);
        }
        finally
        {
          if (error != string.Empty)
          {
            // Если при обработке контейнера произошло исключение, запись в протокол сообщение об ошибке.
            var action = string.Empty;
            if (eventLog.CurrentState == Container.TransferEventLog.CurrentState.InQueue)
              action = Resources.ActionCreateContainer;
            else if (eventLog.CurrentState == Container.TransferEventLog.CurrentState.Creating ||
                     eventLog.CurrentState == Container.TransferEventLog.CurrentState.Sending ||
                     eventLog.CurrentState == Container.TransferEventLog.CurrentState.InProcess)
              action = Resources.ActionSendContainer;
            else if (eventLog.CurrentState == Container.TransferEventLog.CurrentState.Accepted)
              action = Resources.ActionPostprocessDocument;
            
            Container.Functions.TransferEventLog.AddProcessingLog(eventLog, action, error);
            eventLog.CurrentState = Container.TransferEventLog.CurrentState.Error;
            eventLog.Save();
            args.Retry = false;
          }
        }
        
        Locks.Unlock(eventLog);
      }
      else if (args.RetryIteration <= MaxRetryIteration)
      {
        // Подождать разблокировки.
        Logger.DebugFormat("ProcessNextStageForInventory. Ожидание разблокировки Журнала ИД {0}. Итерация: {1}", args.eventLogId, args.RetryIteration);
        args.Retry = true;
        args.NextRetryTime = Calendar.Now.AddMinutes(10);
      }
      
      if (!args.Retry && args.RetryIteration > MaxRetryIteration)
      {
        Logger.DebugFormat("ProcessNextStageForInventory. Не удалось выполнить обработку ИД {0} за максимальное число итераций ({1})", args.eventLogId, MaxRetryIteration);
      }
    }
    
    public virtual void ProcessArchiveDocument(DirRX.Container.Server.AsyncHandlerInvokeArgs.ProcessArchiveDocumentInvokeArgs args)
    {
      args.Retry = false;
      
      if (args.eventLogId == 0)
      {
        Logger.DebugFormat("ProcessArchiveDocument. Невозможно начать обработку, так как передан нулевой ИД журнала.");
        return;
      }
      
      var item = TransferEventLogs.GetAll(x => x.Id == args.eventLogId).SingleOrDefault();
      
      if (item == null)
      {
        Logger.DebugFormat("ProcessArchiveDocument. Невозможно продолжить обработку, так как журнал обработки ИД {0} был удален.", args.eventLogId);
        return;
      }
      
      var rule = item.SelectionRule;
      var moduleName = "DirRX.Container";
      var functionName = rule != null ? rule.ProcessingFunction : "ProcessArchiveDocument";
      
      Logger.DebugFormat("ProcessArchiveDocument. Обработка записи ИД {0}. Правило {1}. Функция {2}.{3}", args.eventLogId, rule != null ? rule.DisplayValue : "Без правила", moduleName, functionName);
      
      var error = string.Empty;
      
      try
      {
        var result = (Container.ITransferEventLog)Functions.Module.ExecuteServerFunction(moduleName, functionName, new object[] { item });
        
        // Если обработка не завершена, назначить повторный вызов обработчика.
        if (result.CurrentState != Container.TransferEventLog.CurrentState.Complete && result.CurrentState != Container.TransferEventLog.CurrentState.Error)
        {
          if (args.RetryIteration < Constants.Module.ProcessingRequestMaxCount)
          {
            args.NextRetryTime = Calendar.Now.AddSeconds(Constants.Module.ProcessingRequestInterval);
            args.Retry = true;
          }
          else
          {
            // Если превысили допустимое число повторных вызовов обработчика, выставить статус "Ошибка".
            error = Resources.ErrorProcessingTimeout.ToString();
            Logger.DebugFormat("ProcessArchiveDocument. Превышено максимальное число итераций {0}.", args.RetryIteration);
          }
        }
      }
      catch (Exception e)
      {
        error = Resources.ErrorProcessingFunctionFormat(e.InnerException != null ? e.InnerException.Message : e.Message);
        Logger.DebugFormat("DirXR.Container.ProcessArchiveDocument. Обработка документа ИД {0}. Ошибка: {1}", args.eventLogId, error);
      }
      finally
      {
        if (error != string.Empty)
        {
          // Если при обработке контейнера произошло исключение, запись в протокол сообщение об ошибке.
          var action = string.Empty;
          if (item.CurrentState == Container.TransferEventLog.CurrentState.InQueue)
            action = Resources.ActionCreateContainer;
          else if (item.CurrentState == Container.TransferEventLog.CurrentState.Creating ||
                   item.CurrentState == Container.TransferEventLog.CurrentState.Sending ||
                   item.CurrentState == Container.TransferEventLog.CurrentState.InProcess)
            action = Resources.ActionSendContainer;
          else if (item.CurrentState == Container.TransferEventLog.CurrentState.Accepted)
            action = Resources.ActionPostprocessDocument;
          
          Container.Functions.TransferEventLog.AddProcessingLog(item, action, error);
          item.CurrentState = Container.TransferEventLog.CurrentState.Error;
          item.Save();
          args.Retry = false;
        }
      }
    }
  }
}