mormot.rest.core--TRestBackgroundTimer

mormot.rest.core--TRestBackgroundTimer

{ ************ 自定义 REST 执行 }

type
  /// TRestServer.Uri() 方法可能执行的所有命令
  // - execSoaByMethod 用于基于方法的服务
  // - execSoaByInterface 用于基于接口的服务
  // - execOrmGet 用于 ORM 读取操作,即 Retrieve*() 方法
  // - execOrmWrite 用于 ORM 写入操作,即 Add、Update、Delete、TransactionBegin、Commit、Rollback 方法
  TRestServerUriContextCommand = (
    execNone,
    execSoaByMethod,
    execSoaByInterface,
    execOrmGet,
    execOrmWrite);

  /// TRest 类执行读取或写入操作的方式
  // - 用于例如 TRestServer.AcquireWriteMode 或
  // TRestServer.AcquireExecutionMode/AcquireExecutionLockedTimeOut
  TRestServerAcquireMode = (
    amUnlocked,
    amLocked,
    amBackgroundThread,
    amBackgroundOrmSharedThread,
    amMainThread);

  /// 用于存储 TRest 实例的执行参数
  TRestAcquireExecution = class(TSynPersistentLock)
  public
    /// 读取或写入操作的执行方式
    Mode: TRestServerAcquireMode;
    /// 在获取锁失败前的毫秒延迟时间
    LockedTimeOut: cardinal;
    /// 后台线程实例(如果有)
    Thread: TSynBackgroundThreadMethod;
    /// 终结内存结构以及相关联的后台线程
    destructor Destroy; override;
  end;
  PRestAcquireExecution = ^TRestAcquireExecution;

  /// 定义 TRest 类如何执行其 ORM 和 SOA 操作
  TRestAcquireExecutions =
    array[TRestServerUriContextCommand] of TRestAcquireExecution;

  /// 服务器端给定客户端连接的真实标识符
  // - 另请参阅 mormot.net.http 中定义的 THttpServerConnectionID,可能映射
  // http.sys ID,或来自递增序列的 31 位真实值
  TRestConnectionID = Int64;

const
  /// 日志大小(以字节为单位),最多记录 2 KB 的 JSON 响应,以节省空间
  MAX_SIZE_RESPONSE_LOG = 2 shl 10;

  /// 您可以使用此 cookie 值在浏览器端删除 cookie
  COOKIE_EXPIRED = '; Expires=Sat, 01 Jan 2010 00:00:01 GMT';

  CONTENT_TYPE_WEBFORM: PAnsiChar = 'APPLICATION/X-WWW-FORM-URLENCODED';
  CONTENT_TYPE_MULTIPARTFORM: PAnsiChar = 'MULTIPART/FORM-DATA';

{ ************ TRestBackgroundTimer 用于多线程处理 }

type
  {$M+}
  { 由于内部耦合,这些类的已发布属性需要 RTTI 信息,
    因此这些类需要在单个 "type" 语句中定义 }
  TRest = class;
  {$M-}

  /// 在 TRest.AsyncRedirect 后台执行后可选调用
  // - 以检索任何输出结果值,作为 JSON 编码的内容
  // - 在 TRestBackgroundTimer.AsyncBackgroundExecute 受保护方法中使用
  TOnAsyncRedirectResult = procedure(const aMethod: TInterfaceMethod;
    const aInstance: IInvokable; const aParams, aResult: RawUtf8) of object;

  /// 能够以定期速度运行一个或多个任务的线程,或进行
  // 带有适当 TRest 集成的异步接口或批处理执行
  // - 例如,由 TRest.TimerEnable/AsyncRedirect/AsyncBatchStart 方法使用
  // - TRest.BackgroundTimer 将定义一个实例,但您可以创建
  // 其他专用实例来实例化分离的线程
  TRestBackgroundTimer = class(TSynBackgroundTimer)
  protected
    fRest: TRest;
    fBackgroundBatch: TRestBatchLockedDynArray;
    fBackgroundInterning: array of TRawUtf8Interning;
    fBackgroundInterningMaxRefCount: integer;
    fBackgroundInterningSafe: TLightLock; // 偏执锁
    procedure SystemUseBackgroundExecute(Sender: TSynBackgroundTimer; const Msg: RawUtf8);
    // 用于 AsyncRedirect/AsyncBatch/AsyncInterning
    function AsyncBatchIndex(aTable: TOrmClass): PtrInt;
    function AsyncBatchLocked(aTable: TOrmClass; out aBatch: TRestBatchLocked): boolean;
    procedure AsyncBatchUnLock(aBatch: TRestBatchLocked);
    procedure AsyncBatchExecute(Sender: TSynBackgroundTimer; const Msg: RawUtf8);
    procedure AsyncBackgroundExecute(Sender: TSynBackgroundTimer; const Msg: RawUtf8);
    procedure AsyncBackgroundInterning(Sender: TSynBackgroundTimer; const Msg: RawUtf8);
  public
    /// 初始化线程以进行定期任务处理
    constructor Create(aRest: TRest; const aThreadName: RawUtf8 = '';
      aStats: TSynMonitorClass = nil); reintroduce; virtual;
    /// 终结线程
    destructor Destroy; override;
  
    /// 在后台线程中定义接口方法的异步执行
    // - 此方法通过一个伪类实现任何接口,该类将所有方法调用重定向到另一个接口的调用,
    // 但作为 FIFO 在与 TimerEnable/TimerDisable 过程共享的后台线程中执行
    // - 参数将被序列化为 JSON 并存储在队列中
    // - 按设计,仅允许没有输出参数的过程方法,因为它们的执行将异步进行
    // - 当然,在 aDestinationInterface 方法执行中引入了轻微的延迟,但主处理线程不再延迟,
    // 并且避免了潜在的竞态条件
    // - 返回的伪 aCallbackInterface 应在销毁 TRest 之前释放,以释放重定向资源
    // - 这是解决 SOA 回调中最难实现问题的优雅方案,即避免重入时的竞态条件,
    // 例如,如果回调从一个线程运行,然后回调代码尝试在初始线程的上下文中执行某些操作(由临界区(互斥锁)保护)
    procedure AsyncRedirect(const aGuid: TGuid;
      const aDestinationInterface: IInvokable; out aCallbackInterface;
      const aOnResult: TOnAsyncRedirectResult = nil); overload;
  
    /// 在后台线程中定义接口方法的异步执行(重载版本)
    // - 功能与上一个 AsyncRedirect 方法类似,但允许通过 TInterfacedObject 实例指定目标
    procedure AsyncRedirect(const aGuid: TGuid;
      const aDestinationInstance: TInterfacedObject; out aCallbackInterface;
      const aOnResult: TOnAsyncRedirectResult = nil); overload;
  
    /// 准备在后台线程中执行的异步 ORM BATCH 过程
    // - 将初始化 TRestBatch 并调用 TimerEnable 以初始化后台线程,根据给定的处理周期(以秒为单位),
    // 或 TRestBatch.Count 阈值来调用 BatchSend
    // - 实际的 REST/CRUD 命令将通过 AsyncBatchAdd、AsyncBatchUpdate 和 AsyncBatchDelete 方法进行
    // - 除非使用 AsyncBatchStop 方法刷新当前的异步 BATCH,否则每个表只允许调用一次 AsyncBatch()
    // - 在专用线程中使用 BATCH 将允许非常快速的后台异步处理 ORM 方法,足以满足大多数用例
    function AsyncBatchStart(Table: TOrmClass;
      SendSeconds: integer; PendingRowThreshold: integer = 500;
      AutomaticTransactionPerRow: integer = 1000;
      Options: TRestBatchOptions = [boExtendedJson]): boolean;
  
    /// 终结在后台线程中执行的异步 ORM BATCH 过程
    // - 应先调用 AsyncBatch(),否则返回 false
    // - Table=nil 将释放所有现有的 batch 实例
    function AsyncBatchStop(Table: TOrmClass): boolean;
  
    /// 在要在后台线程中写入的 BATCH 中创建一个新的 ORM 成员
    // - 应先调用 AsyncBatchStart(),否则返回 -1
    // - 是 Timer 线程中发送的 TRestBatch.Add() 的包装器,
    // 因此将返回 BATCH 行中的索引,而不是创建的 TID
    // - 此方法是线程安全的
    function AsyncBatchAdd(Value: TOrm; SendData: boolean;
      ForceID: boolean = false; const CustomFields: TFieldBits = [];
      DoNotAutoComputeFields: boolean = false): integer;
  
    /// 在要在后台线程中写入的 BATCH 中附加一些 JSON 内容
    // - 可用于模拟已预先计算 JSON 对象的 AsyncBatchAdd()
    // - 是 Timer 线程中发送的 TRestBatch.RawAdd() 的包装器,
    // 因此将返回 BATCH 行中的索引,而不是创建的 TID
    // - 此方法是线程安全的
    function AsyncBatchRawAdd(Table: TOrmClass; const SentData: RawUtf8): integer;
  
    /// 在要在后台线程中写入的 BATCH 中附加一些 JSON 内容
    // - 可用于模拟已存储在 TJsonWriter 实例中的 AsyncBatchAdd()
    // - 是 Timer 线程中 TRestBatch.RawAppend.AddNoJsonEscape(SentData) 的包装器
    // - 此方法是线程安全的
    procedure AsyncBatchRawAppend(Table: TOrmClass; SentData: TJsonWriter);
  
    /// 在后台线程中要写入的 BATCH 中更新 ORM 成员
    // - 应先调用 AsyncBatchStart(),否则返回 -1
    // - 是 Timer 线程中发送的 TRestBatch.Update() 的包装器
    // - 此方法是线程安全的
    function AsyncBatchUpdate(Value: TOrm;
        const CustomFields: TFieldBits = [];
        DoNotAutoComputeFields: boolean = false): integer;
  
    /// 在后台线程中要写入的 BATCH 中删除 ORM 成员
    // - 应先调用 AsyncBatchStart(),否则返回 -1
    // - 是 Timer 线程中发送的 TRestBatch.Delete() 的包装器
    // - 此方法是线程安全的
    function AsyncBatchDelete(Table: TOrmClass; ID: TID): integer;
  
    /// 允许对指定的 RawUtf8 字符串池进行后台垃圾收集
    // - 默认情况下,将每 5 分钟运行 Interning.Clean(2)
    // - 设置 InterningMaxRefCount=0 以禁用 Interning 实例的处理过程
    procedure AsyncInterning(Interning: TRawUtf8Interning; InterningMaxRefCount: integer = 2; PeriodMinutes: integer = 5);
  
    /// 直接访问 TRest 实例所有者
    property Rest: TRest read fRest;
  
    /// 直接访问后台线程中的 TRestBatch 实例
    property BackgroundBatch: TRestBatchLockedDynArray read fBackgroundBatch;
    published
    /// 线程的标识符,用于日志记录
    property Name: RawUtf8 read fThreadName;
end;

// 向后兼容类型重定向
{$ifndef PUREMORMOT2}

TSqlRestServerUriContextCommand = TRestServerUriContextCommand;
TSqlRestServerAcquireMode = TRestServerAcquireMode;
TSqlRestAcquireExecution = TRestAcquireExecution;
TSqlRestBackgroundTimer = TRestBackgroundTimer;

{$endif PUREMORMOT2}
posted @ 2024-07-12 18:12  海利鸟  阅读(25)  评论(0编辑  收藏  举报