Subscriber counts on our instance were off by a huge margin and negative for some subs. On investigation we spotted this pattern which the peewee docs say specifically to not do:
sub.subscribers += 1
sub.save()
The reason to not do it this way is that it is vulnerable to race conditions if another request is simultaneously subscribing or unsubscribing.
That turned out not to be the main problem with subscription counts, which was that register was not updating them when it subscribed new users to the default subs.
This PR:
Reduces the number of calls to Model.save, to simplify code and reduce the number of places that need to be reviewed for possible race conditions.
Changes all the usages of save similar to the example above to use Model.update, as recommended by the peewee docs.
Fixes the register bug and a couple of other places where the subscriber count wasn't getting updated.
Adds the beginning of a command line framework based on click and flask.cli
Running ./throat.py works as before, but now ./throat.py recount subscribers will recalculate the subscriber counts for all the subs, and it has a --dry-run option if you would like to see what it is going to do before it does it.
Subscriber counts on our instance were off by a huge margin and negative for some subs. On investigation we spotted this pattern which the peewee docs say specifically to not do:
The reason to not do it this way is that it is vulnerable to race conditions if another request is simultaneously subscribing or unsubscribing.
That turned out not to be the main problem with subscription counts, which was that
register
was not updating them when it subscribed new users to the default subs.This PR:
Model.save
, to simplify code and reduce the number of places that need to be reviewed for possible race conditions.save
similar to the example above to useModel.update
, as recommended by the peewee docs.register
bug and a couple of other places where the subscriber count wasn't getting updated.click
andflask.cli
./throat.py
works as before, but now./throat.py recount subscribers
will recalculate the subscriber counts for all the subs, and it has a--dry-run
option if you would like to see what it is going to do before it does it.