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}