fix(search): the API-sourced live search takes its slot under the lock too

Checked first and logged after search.list, requests sent together at the
last free slot all passed, and each spent 100 units of the shared budget.
Every live search now claims its slot (quota.claim_action) whatever the
source, and gives it back when it showed nothing. The cap counts the
zero-unit claims only, so search.list's own spend event is accounting,
not a second slot. log_action, the unlocked writer, goes.

Tests: the API source reads one page per request, is refused before the
call when the budget cannot pay, counts one slot per search and refunds a
failed one; the lock test now proves the count happens after the lock.
This commit is contained in:
2026-10-25 02:50:34 +02:00
parent 005784e291
commit ed51f5be7e
6 changed files with 133 additions and 55 deletions
+3 -2
View File
@@ -336,10 +336,11 @@ def test_the_last_slot_is_taken_under_a_lock(db, make_user):
t.start()
t.join(timeout=1)
assert t.is_alive() # it waits for the one holding the lock
# ...and counts only once it has the lock: the one holding it takes the last slot meanwhile.
db.add(QuotaEvent(user_id=user.id, action=action, units=0))
db.commit()
t.join(timeout=10)
assert got and got[0] is not None
assert quota.claim_action(user.id, action, 1) is None # the one slot is taken
assert got == [None]
def _videos_list_fails(monkeypatch, *, on_call: int = 1, reason: str = "quotaExceeded") -> None: