kbss-cvut / termit

An advanced SKOS terminology manager linking concepts to their definitions in documents
GNU General Public License v3.0
8 stars 9 forks source link

Method Throttling #295

Closed lukaskabc closed 1 month ago

lukaskabc commented 1 month ago

This PR addresses performance issues from #287 and #285

Identified problems

New features

Throttle & Debounce

This PR introduces an option to throttle and debounce method calls.

method throttling & debouncing

Do not review linked test cases before reading about return type support and throttled futures

The goal of method throttling & debouncing is to execute tasks asynchronously on a fixed thread pool merging often method calls into a single task execution with the newest data from the most recent method call [test case]. Throttling ensures that if the method task were not executed in the last X seconds, it would be scheduled for immediate execution [test case]. Otherwise, its execution will be delayed (debounced) so that it can be merged with potential future calls (it guarantees that when no future call comes, the task will be executed with the data from the last call). Task execution also ensures that when a task is time-consuming and its execution is taking longer than the actual throttle interval, a new call to the throttled method won't result in the concurrent execution of the same task [test case]. When a thread is already executing a throttled task, it will ignore any further throttling and will execute all methods synchronously [test case].

Throttling & Debouncing is realized with the Throttle annotation which is handled by the Throttle aspect.

Aspect is configured using Spring AOC XML syntax to not utilize AspectJ. Once AspectJ is removed from dependencies, it should be possible to replace XML configuration with annotations. Aspect is disabled for the test profile.

Throttle annotation supports methods with void return type out of the box. The whole method is, in that case, considered a task that should be throttled, and the method itself will be executed asynchronously.

There is also support for methods returning a Future. However, the concrete returned object MUST be ThrottledFuture. Otherwise the aspect will throw appropriate exception on the method call (there is no way to safely check that on application start). When a method returns future (ThrottledFuture), the method itself will be executed synchronously allowing to prepare the task that should be throttled and also to provide a cached result which may be acquired by a caller method from CacheableFuture interface before the actual future resolution. The actual task and cached result is then provided through the returned ThrottledFuture object. An example can be seen in updated result caching validator where the method validate will be executed synchronously by the caller thread, checking the cache state and returning already resolved future when the cache is not dirty, or returning the future with the time-consuming task runValidation method and providing the cached result. Method runValidation will be executed asynchronously.

Throttled future also implements a chainable future interface, which allows to chain a task that will be executed once the future is resolved. This, for example, allows the WebSocket controller to respond with the cached result and set a task that will send a new result to the client once new data are available. This prevents the thread from being blocked while awaiting a future resolution.

Scheduling throttled futures also support their cancellation based on their group.
This, for example, allows to cancel scheduling a task to analyze a definition of a single term while an analysis of all terms from the vocabulary is scheduled.

Disadvantages

Long-running tasks

As the application will now run some time-consuming tasks in the background, it will push the status of such tasks to the clients via WebSocket, allowing to display information about the activity to the user.

Currently, it's only possible to name the throttled method by a constant. So, the user will know that there is a validation in progress but won't know which vocabulary is being validated. This might be changed by adding a new parameter for additional information (in addition to the name parameter).

Changes

Requirements and notes