Add support for parallel input event handler
See original GitHub issueI try to encourage Lona users to use callback based input event handler to make their apps more scaleable, but currently input event handler run serialized.
Let’s say we have two buttons. The first button triggers a long running operation (getting a value from a database), the second triggers a short running operation (toggling a popup). When the first button is pressed the popup can’t be opened or closed, until get_count_from_database()
is done. For the end-user the app then feels slow and unresponsive.
from lona.html import HTML, H1, Span, Button
from lona import LonaView
from my_code import long_running_database_call, Modal
class MyLonaView(LonaView):
def get_count_from_database(self, input_event):
self.count = long_running_database_call()
def toggle_modal(self, input_event):
self.modal.toggle()
def handle_request(self, request):
self.counter = Span()
self.modal = Modal()
return HTML(
H1('The count from the database is: ', self.counter),
self.modal,
Button(
'Get count from Database',
handle_click=self.get_count_from_database,
),
Button(
'Toggle modal',
handle_click=self.toggle_modal,
)
)
You can solve this issue by runnnig get_count_from_database()
in a thread, but i think we can automate this.
My idea is to allow parallel execution of input event handlers in the server, but very limited. I think we can’t just use a thread for every click a user makes (that would be ascalability nightmare), but we can make the count of parallel input event handler configurable in the settings.
I would propose 2
as default. With two parallel handlers you can run one long running call and service input like button presses, without handling threading by yourself.
Issue Analytics
- State:
- Created 10 months ago
- Comments:11 (11 by maintainers)
Top GitHub Comments
Totally agree
I did some experiments and i realized just limiting, the jobs a view can run simultaneously, to a finite number, has multiple problems:
No great solution for “power-clicking”. The proposed solution would give the user one thread for long running tasks, and one for short running tasks, to make the app feel fast and responsive, but nothing to distinguish between these two kinds of work-load. This means, if you have one button, that triggers a long running operation and you click it two times, you will have the initial problem, i try to solve here, on the third click.
Designed bottleneck. Setting a finite number would mean that, even if you are the only user of a machine with 10 cores and 100 threads running, your clicks are bottlenecked to
2
(or another number).Priorities instead of limits
I think a better solution for this is to not limiting parallel jobs, but to prioritize them: All input events get pushed into one
PriorityQueue
with a timestamp as their priority. Per view we have a counter of pending input events, that gets incremented on an incoming input event, and decremented when an input event got handled.When an input event comes in, it gets put into the queue with its priority set to
(now() + timedelta(seconds=pending_input_events)).total_seconds
.This way “power-clicking” would be accounted for, and slow only one user down, but not his neighbors, this scales up and down and parallel execution would be possible.
Why timestamps? In this context they are called deadlines and ensure that jobs can be prioritized, but can’t get stuck in the queue indefinitely. If we would use a base priority of
1
, views with only short running jobs would never decrease their priority and would clog the top of the queue.