mormot.rest.core--TRestBackgroundTimer

海利鸟發表於2024-07-12

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}