Delphi 在intraweb用户会话中实现服务器计时器的正确方法是什么

Delphi 在intraweb用户会话中实现服务器计时器的正确方法是什么,delphi,timer,intraweb,Delphi,Timer,Intraweb,我有一个简单的intraweb项目,其结构如下 用户会话: 有一个计时器来检查数据库并加载更改,进行一些数据格式化,并将结果放入内存表中 主要表格: 使用IWTimer检查Usersession中的内存表是否已更改,并在需要时更新其内容 我不使用IWTimer直接检查数据库,因为我不希望在浏览器中有影响用户体验的等待时间 问题是usersession似乎没有消息队列,普通计时器无法工作。所以,我在绝地VCL中使用了JvThreadTimer。我在UserSession中创建它。创建事件并在Des

我有一个简单的intraweb项目,其结构如下

用户会话: 有一个计时器来检查数据库并加载更改,进行一些数据格式化,并将结果放入内存表中

主要表格: 使用IWTimer检查Usersession中的内存表是否已更改,并在需要时更新其内容

我不使用IWTimer直接检查数据库,因为我不希望在浏览器中有影响用户体验的等待时间

问题是usersession似乎没有消息队列,普通计时器无法工作。所以,我在绝地VCL中使用了JvThreadTimer。我在UserSession中创建它。创建事件并在Destroy事件中停止并释放它。它做得很好

但是,当我关闭服务器应用程序时,它会立即弹出EidClosedSocket,并显示消息“Disconnected”。在MainForm/Usersession/ServerControl Unit中的Destroy事件之前触发的异常,因此我无法在计时器触发异常之前找到停止计时器的方法

那么,在usersession中是否有一种正确的方法来设置服务器端计时器,或者是否有其他不影响浏览器使用的定期数据库检查方法


提前感谢您的帮助。

首先。不要在非窗口应用程序(如服务/Web服务器)中使用VCL内容和依赖窗口句柄的内容

要满足这一要求,最简单的方法是使用一个带有事件对象的线程,该对象在应用程序启动时被调度

它应该是这样的:

type
  TTimerThread = class(TThread)
  private
    fSig : TSimpleEvent;
    procedure DoTimer;
  protected
    procedure Execute; override;
  public
    procedure SignalTerminate;

    constructor Create;
    destructor Destroy; override;
  end;

{ TSessionGarbageCollector }

constructor TTimerThread .Create;
begin
     fSig := TSimpleEvent.Create;

     inherited Create(False);
end;

destructor TTimerThread.Destroy;
begin
     fSig.Free;

     inherited;
end;

procedure TTimerThread.Execute;
begin
     try
        // e.g. every 10 seconds
        while fSig.WaitFor(10000) = wrTimeout do
        begin
             if Terminated then
                break;

             try
                // #################################################
                // #### Run the garbage collector from time to time
                DoTimer;
             except
                   on E : Exception do
                   begin
                        // your timer specific exception handling here
                   end;
             end;
        end;
     except
           on F : Exception do
           begin
                // your global exception handling here 
           end;
     end;
end;

procedure TSessionGarbageCollector.DoTimer;
begin
     // whatever you like your timer to do
end;

procedure TSessionGarbageCollector.SignalTerminate;
begin
     Terminate;

     fSig.SetEvent;
end;

还请注意,如果模块是dll(如isapi dll),则不应在initialization子句中调度线程。寻找一个你知道dllmain已经被处理过的地方。

谢谢你的回答。我测试了您的代码,问题与使用TJvThreadTimer完全相同。实际上,您的代码对TJvThreadTimer也有类似的作用。问题是,在引发异常之前,我找不到调用线程停止的位置。此外,由于未触发on异常,Execute方法中未发生异常。什么异常?您需要显示一些代码,以便我们可以查看您如何使用计时器。要停止此线程,需要调用aTimer.SignalTerminate;阿蒂默·韦特;免费的;按照这个顺序,问题中已经出现了例外。带有消息“Disconnected”的EID ClosedSocket。我在代码中添加了两个属性,即interval和OnTimer事件。我在usersession的OnCreate事件中创建对象。它在每个间隔调用OnTimer事件时都工作得很好。但是,当我终止活动会话或关闭调试窗体中的生成时。此时会出现EidClosedSocket异常弹出窗口。调用堆栈显示它在InIOHandler中。只要有一个可以在异常之前执行的位置,您的终止过程就可以了。异常是一个完全不同的故事。此异常与计时器本身无关。如果在计时器例程中发生这种情况,您需要在那里处理/吞咽它(不要让异常从线程中逃逸)。谢谢您的建议。我知道这个异常并没有直接发生在计时器中。但它只存在于有活动线程计时器的地方。这就是为什么我要问在这种情况下实现计时器的正确方法是什么。