Repository: rotki/rotki

Issue:
Improve task status retrieval
## Problem Definition

The task mechanism currently doesn't provide an easy way to check which tasks are done in a single call. This means that every running task has to be polled every x (currently 2) seconds.

For endpoints like the transactions, or exchange trades, where we do requests per account or per exchange this means that we are polling for each task while the status is pending.
![image](https://user-images.githubusercontent.com/2269732/102485295-b3f63b80-4067-11eb-8b52-0158f09f2791.png)

### Proposal

The proposed solution is to make the tasks GET call to return the status for all the tasks that have been not requested by the client.

This would return something like the following
```json 
{
 "pending": [1,2,3],
 "complete": [4]
}
```

Then the frontend instead of polling each different task endpoint while the tasks are pending it will just poll all tasks endpoint.
It will only call the specific task endpoint after the task is complete.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/api/rest.py b/rotkehlchen/api/rest.py
--- a/rotkehlchen/api/rest.py
+++ b/rotkehlchen/api/rest.py
@@ -286,8 +286,17 @@ def get_settings(self) -> Response:
     @require_loggedin_user()
     def query_tasks_outcome(self, task_id: Optional[int]) -> Response:
         if task_id is None:
-            # If no task id is given return list of all pending/completed tasks
-            result = _wrap_in_ok_result([greenlet.task_id for greenlet in self.killable_greenlets])
+            # If no task id is given return list of all pending and completed tasks
+            completed = []
+            pending = []
+            for greenlet in self.killable_greenlets:
+                task_id = greenlet.task_id
+                if task_id in self.task_results:
+                    completed.append(task_id)
+                else:
+                    pending.append(task_id)
+
+            result = _wrap_in_ok_result({'pending': pending, 'completed': completed})
             return api_response(result=result, status_code=HTTPStatus.OK)
 
         with self.task_lock:


Test patch:
diff --git a/rotkehlchen/tests/api/test_async.py b/rotkehlchen/tests/api/test_async.py
--- a/rotkehlchen/tests/api/test_async.py
+++ b/rotkehlchen/tests/api/test_async.py
@@ -36,7 +36,7 @@ def test_query_async_tasks(rotkehlchen_api_server_with_exchanges):
     assert_proper_response(response)
     json_data = response.json()
     assert json_data['message'] == ''
-    assert json_data['result'] == []
+    assert json_data['result'] == {'completed': [], 'pending': []}
 
     # Create an async task
     with binance_patch:
@@ -52,7 +52,8 @@ def test_query_async_tasks(rotkehlchen_api_server_with_exchanges):
         assert_proper_response(response)
         json_data = response.json()
         assert json_data['message'] == ''
-        assert json_data['result'] == [task_id]
+        assert json_data['result'] == {'completed': [], 'pending': [task_id]}
+        # assert json_data['result'] == {'completed': [], 'pending': []}
 
         # now query for the task result and see it's still pending (test for task lists)
         response = requests.get(
@@ -126,7 +127,7 @@ def mock_binance_asset_return(url):  # pylint: disable=unused-argument
     assert_proper_response(response)
     json_data = response.json()
     assert json_data['message'] == ''
-    assert json_data['result'] == [task_id]
+    assert json_data['result'] == {'completed': [task_id], 'pending': []}
 
     while True:
         # and now query for the task result and assert on it