Thread, Timer, Listbox Problem

I am working on a time-of-use reporting and billing project for electric submeters. Both the billing and reporting functions call the same thread to extract the time-of-use data from the log of meter readings. The thread writes the data to a table in an SQLite database that is cleared at the start of each operation. The problem is in the reporting function. Normal operation would have a timer start just before running the thread. The timer updates a progress bar and when it is complete, it closes the progress bar dialog and kills the thread. It then calls either the summary report or the detailed report as appropriate. The summary report works fine. The detailed report code all executes and when the report method completes, a Javascript error fills the entire listbox where the report should appear. If I change the code at this point so that calling for the report calls the report method without calling the thread/timer routine that generates the data, the report works as expected.

Initially, I was using a WebTimer that continued to run after its mode was set off and thought this was the source of my problem. Michel Bujardet suggested changing to a server side timer (https://forum.xojo.com/37847-timer-does-not-stop-firing/p1#p308678). Now the timer stops when it should but I still get the error. At one point I added another WebTimer that was started by the server side timer. The WebTimer called the routine to generate the report. With this configuration, the crash comes not after the last command of the report method as previously, but after the WebTimer.Action closes.

The error message begins Could not execute returned javascript: Index or size is negative or greater than the allowed amount and continues with everything that appears in the report when it works properly.

Unfortunately those dialogs show up ou the complete source that was being run when the error occurred, not just the problem code, so it’s very hard to diagnose from that sometimes.

The error could be any number of things, but my first instinct is to ask… how are you keeping track of which session that server-side timer belongs to?

Also, how much data are you showing on screen? It might be worth not only updating a progress bar but also sending some data down at the same time if you can.

I wasn’t doing anything about a session reference in the timer, but it did not seem to be an issue because the data in the error message was correct. I just added a new first line in the timer action: [quote]dim context As New WebSessionContext(mySession) [/quote] . Unfortunately, it did not help. For testing I am only sending 13 lines of data to a listbox. I am really baffled because the report routine works fine if it is called from a separate button, but it crashes if called from a timer. But another report works fine if called from the same timer.

Let’s address that first item first.

All requests that come from a browser are WebThreads (a subclass of Thread which has an internal knowledge of which Session they belong to)

WebTimers also “know” which Session they are on as they actually fire in the browser and end up creating one of the aforementioned WebThreads.

Plain old Timers do not have this mechanism. This means that when a Timer fires, its Action event fires on the Main Thread with no association to any particular Session.

What all this means is that the code that’s running in the Timer may or may not be sent to the correct session if you don’t do some hinting of your own. There are a few possibilities, such as keeping a weak ref to the session somewhere and just being careful to check its state whenever you use it, or if the timer only updates one control, keep a weakref to that control.

Thank you Greg for the clear explanation of the differences between the timers. I am sure that not having the proper session reference was part of the problem, but the problem didn’t go away until I found two places in my code where I set listbox.heading=false and removed one of them. I never did figure out why the WebTimer kept running after its mode was set off, but using the server-side timer works now that I have a session reference.