Is there a way to run code asynchronously (non-blocking) in the client?
I would like the client to make many (eg. 10) server calls simultaneously. Without the client waiting for the first call to complete before it makes the second call.
Background tasks are server side so sadly enough do not solve this.
I could probably implement this myself with a little javascript (and http endpoints), but then I lose all the automatic python serialization which is kind of sad
You can call a background task indirectly, i.e., call a server function that creates the background task, and returns the task handle. So, while the background task is busy populating a result (dictionary), the client can poll the handle (e.g., at timed intervals) to discover what new data items have been added.
Yeah, I was actually thinking about something like this. Would be nice if we could get an abstracted system for something like this with annotations (eg. being able to push events from the server’s background threads to the client)
I think being able to populate your UI asynchronously would be really, really nice, yes. Of course there are ways to optimize things as they are, but this would make everything a lot easier development wise.
Well, little late to the party… But I also needed to load component data in an aync manner.
In my case, I have a repeating panel with a complex layout, each one takes 2-5 seconds to populate including fetching image and scraping remote site data from an uplink server function.
Don’t do that!
It is dangerous to create your own threads. If you start working with data tables or other services, you could have nasty side effects. Plus they could be killed at will without notifying you.
The correct way is to use background tasks.
The difference is that the server will take care of keeping everything safe when concurrent threads access the same services.
This sound almost like you are doing the row['fetched'] = False on the client. If this is not the case, then you are doing the right thing.
If you are really changing one column of one row from the client, you are:
Doing something unsafe. Your form has access to that row → anyone can do anything on your row, and perhaps on your database. It’s always safer not to give write access to the client (I don’t even give read access)
You are doing things the slow way. You are already calling the server to fetch something, the server should set that value during the same call. It would be much faster (I hope that’s what you are already doing)
See this post: MVC Architecture Demo - #13 by owen.campbell about a new feature in Anvil Labs (the experiments that might eventually make their way into Anvil Extras) allowing asynchronous server calls.
I made sure the write operations are thread safe. Other than that what are the dangers we talking about? And, In my case, I don’t care about the thread getting killed, All it’s doing is trying to get data in case certain columns in my row is missing.
row['fetched'] = False was indeed on the client code while i was testing, later i moved it to server.
Without giving write access i lose the sweet flavor of anvil’s live proxy object.
That server call takes about 5 seconds! so, doing this in a single call is actually slower in my particular case, that’s the reason i had to do all these!
I had apps using threads before the background tasks existed, and they were crippled with bugs. I couldn’t print, accesses to the database were failing, they were crashing, they were failing because killed half way, etc.
The fact that you have been lucky so far using using threads doesn’t make it the right way. Background tasks have been designed to do that job, to be monitored, to report the status, to last longer than the caller’s request and than the 30 second timeout, and to play nice with all the rest of Anvil infrastructure.
Said that, there may be simple cases where threads don’t pose any risks and background tasks would introduce useless overhead.
It’s sweet and unsafe. It’s ok to use it when you play around, but you need to know that you are opening that sweet door for yourself and for the rest of the world. Whatever you can do from the form, any hacker can do it.
I have the feeling that the 5 seconds are the sum of the server call plus all the round trips triggered because you play with row objects on the client side. Obviously I don’t know if it’s 4+1 or 1+4.
I don’t know what you are doing with the row objects on the client side, but when someone talks on the same post about both using row objects on the client side and performance problems, 9 times out of 10 that’s the problem.
Summary: I saw a couple of flags to be risen, and I did rise them
Ok, so since I read what @rsmahmud did yesterday I was thinking how I would do the same thing, using just:
components
timer components
background tasks
Today I made a short example of async like behavior that does what @rsmahmud wants, but uses background tasks instead:
It can still be optimized further, especially if used with other techniques to chunk the server calls into blocks that only cover what the user might want to see on one page (like a lazy loading type behavior, etc.)
Using one timer per component is a very nice approach.
The main form doesn’t even know about it!
One way to optimize it would be to have only one timer on the main form that makes one call that returns the result of all the background tasks that are ready at once. I assume a round trip is required every time a component calls task_value = self.task1.get_return_value(), so, instead of having 10 timers pinging the server at the same time, you only have one.
This solution would decrease the number of round trips, but would make the components more complex. The component should expose attributes like need_to_be_checked and set_result.
Why did you decide to remove it from the parent? I would have set the interval to zero.
I tried both, I found it made no difference, it was the last thing I did after I posted the link.
I guess I was kind of just was wondering if it would also work? When I pushed it to like 100 elements it hangs while starting all of those background tasks.
Also, yes, my initial impulse was to create some kind of task stack to run through, with callbacks and raising events and all that, but then I decided to keep it as simple as I could to show off timers and background tasks if a new user wanted to clone it.
You could even create a background task to scroll through a list of tasks to monitor the other background tasks, using the task state of this ‘meta task’ to communicate the ID of each task and whether it was finished or not, using something like .task_state[task_id]