Here is what I have got from Codex:
A timer inside a filter is generally the wrong design.
Suppose the filter does this:
Sub Class_Globals
Private tmr As Timer
End Sub
Public Sub Initialize
tmr.Initialize("tmr", 1000)
tmr.Enabled = True
End Sub
Because each request gets a new filter instance, the practical result is:
Request 1 → filter instance 1 → timer 1
Request 2 → filter instance 2 → timer 2
Request 3 → filter instance 3 → timer 3
...
An enabled timer remains referenced by the message queue, so its filter instance may also remain alive. You can therefore accumulate timers and filter objects instead of having one shared timer.
There is another problem:
- AddFilter(..., False) executes the filter on a server-pool thread.
- That request thread normally finishes after Filter returns and does not maintain a message loop.
- Consequently, Timer_Tick should not be expected to execute reliably there. This commonly works in Debug but fails in Release—a behavior reported and explained in this B4X forum discussion.
Do not solve this by calling StartMessageLoop inside a normal filter: that would hold a server request thread and potentially prevent the HTTP request from completing.
The clean design is one persistent timer outside the filter:
'Main module
Sub Process_Globals
Private CleanupTimer As Timer
End Sub
Sub AppStart(Args() As String)
CleanupTimer.Initialize("CleanupTimer", 1000)
CleanupTimer.Enabled = True
srvr.AddFilter("/*", "MyFilter", False)
srvr.Start
StartMessageLoop
End Sub
Private Sub CleanupTimer_Tick
'Periodic application-wide work
End Sub
Then the lifecycle is:
Main/application → one persistent timer
Each request → temporary filter instance → Filter(...)
If the timer needs its own isolated thread, put it in a jServer background worker and call StartMessageLoop in that worker. Erel recommends background workers for persistent server-side timer work in this
server timer discussion.
I suppose you could reform your RateLimiter filter to BackGroundWorker and then run in a filter module the code inside this worker with code like wrk.Filter(.......) inside the Filter sub of the filter.