I think here lies the problem. You are calculating the previous vote before sending this signal, which means that when the signal is received, the previous vote may be outdated. For example, assuming we have a user who had already downvoted a submission and upvotes it twice now really fast (double-clicking), this can be a legitimate way of executing two votes:

1. Receive POST request for upvote, run `post_thumbs`
2. Receive POST request for upvote, while running `post_thumbs`, so queue up `post_thumbs` to run after that.
3. `post_thumbs` sends `thumbs_finished` signal with `prev_vote == False` and `vote == True`.
4. `post_thumbs` runs again for the second POST requests, sends another `thumbs_finished` signal. Since the other signal has not been received yet, it also sends it with `prev_vote == False` and `vote == True`.
5. When the two signals are received, each will be treated separately, and in both cases, the new reputation will be updated by 2.

This is one of the problems with running things async: you have to be sure that the things you are handling are the latest ones. Don't get the previous vote now; get it on the signal receiver, instead. When things run asynchronously, you can't make any assumptions about the state of the environment (such as the database).