[optional] I don't like much that we call _acquire_lock in one scope and release it in another. It would be better if all the logic to check if a task is valid (not duplicate) and to release such information is in the same place.

One way to do that in python is to use context managers. Something like this:

```python
# just a sketch

with valid_task(task_id):
  ... run the task

def valid_task(task_id):
  ... check if task is valid
  ... adcquire locks
  ... raise exception if not
  yield task_id
  ... release locks
```
 

``