Client-side Background Tasks

For example, using the browser’s idle time to do housekeeping, and stay up-to-date with external events. Should not interrupt UI.

3 Likes

I use a timer for this.
It is not as refined as a background task, but it does the job.
It shouldn’t be difficult to create a custom component that accepts a callable, with start, kill, etc. methods, that uses a timer to simulate a background task.

With a timer,

  1. How do you avoid interrupting (or slowing) the user’s UI activities, given that they may start and stop at any time?
  2. How do you keep the timer running, when switching forms?
1 Like
  1. That entirely depends on the code you are running in the timer and how often it runs.

  2. It wouldnt keep running because they would be different timer components. You would have to do some work with the Messaging component from Anvil Extras in conjunction with a Timer to work that out.

…and this is why I’m making it a Feature Request. Because

  1. It’s anything but obvious how to effectively break up many kinds of tasks into parts that are small enough to avoid interrupting the user. (Although yield and async may provide a clue…)
  2. In the general case, timers aren’t enough. (Maybe you could manage to move the timer from Form to Form…)
1 Like

Fair points. If you are wanting the background tasks to actually run on the client, I think that’s always going to risk performance concerns. If you jist want a way to run client triggered background tasks, that sounds like a significantly new feature to develop.

Moving a timer from form to form wouldn’t work because even if they were identical in content and config, they would be different instances.

Well, there’s a reason I wrote

(emphasis mine).

What sparked this idea: the term “web workers” came up while I was reading about browser-side storage. I may be getting the idea wrong, but it seems like these might be the very definition of background tasks.

I use a global status variable for the background task, stored either on the form or on a Globals module.

The background task should be designed to get the last execution’s status from the global variable, execute a small unit of work, store the status and get out. The concept is similar to an event loop, where the global variable contains the todo list.

I usually use a timer per form because my background tasks are usually restrained to one form, and I like that the timer stops ticking when the form disappears.

If you want the background task to keep running when the form changes, (assuming you too use one main form that loads sub-forms, either manually or with hashrouting), you could put the timer on the main form.

Or the custom component could be configured to continue the job started by the previous form, using the same variable stored in the Globals module.

I agree!
I replied offering my solution, which “is not as refined as a background task, but it does the job.”

Using a timer for background tasks still comes natural to me, more than using threads, because I worked for many years in VB6, and that’s how you simulate multi-threading in VB6 (sadly enough I still maintain libraries that are 25+ year old. In VB6. On Windows 10).

2 Likes

I very much appreciate your interim solution.

For what it’s worth, I had to do similar things back in MS-DOS. The Vitamin C library (a TUI) ran its own event loop, and so it knew when it had run out of input events. It provided a “hook” function (callback) to be invoked at such “idle” times. Without pre-emptive threading, we had to limit the amount of work being done, just as you describe, to occupy no more than 0.1 seconds, otherwise the user would notice.

There seems to be no concept, in Anvil’s Client, of an “on idle” event. That would be one step in this direction.

Since we’re talking event loops, here, it probably makes sense to think of this in terms of Python’s async features, which formalize and standardize the event loop, in a portable manner.

Doing it that way would be more Python-standard.

Edit: Not that I can wrap my head (or code) around async right now…

2 Likes

Coincidentally, I just found out that asyncio doesnt work with skulpt yet, so that wouldnt even be an option in the cliemt right now.

async would be the “Pythonic” way to deal with these things.

After a (quick) visit to skulpt’s github repository, I didn’t see any sign that skulpt is working on async.

2 Likes