50 lines
1.3 KiB
Python
50 lines
1.3 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import logging
|
|
from collections import defaultdict
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SequentialQueue:
|
|
def __init__(self):
|
|
self._queues: dict[str, asyncio.Queue] = defaultdict(asyncio.Queue)
|
|
self._processing: dict[str, bool] = defaultdict(lambda: False)
|
|
self._lock = asyncio.Lock()
|
|
|
|
async def process(self, key: str, handler, item) -> None:
|
|
queue = self._queues[key]
|
|
await queue.put(item)
|
|
|
|
async with self._lock:
|
|
if self._processing[key]:
|
|
return
|
|
self._processing[key] = True
|
|
|
|
try:
|
|
while True:
|
|
entry = await queue.get()
|
|
|
|
try:
|
|
await handler(entry)
|
|
except Exception:
|
|
logger.exception("Error processing sequential item for key %s", key)
|
|
|
|
if queue.empty():
|
|
break
|
|
finally:
|
|
async with self._lock:
|
|
self._processing[key] = False
|
|
|
|
|
|
def get_sequential_key(msg: dict, account_id: str) -> str:
|
|
chat_id = ""
|
|
group = msg.get("group")
|
|
if group:
|
|
chat_id = group.get("id", "")
|
|
else:
|
|
sender = msg.get("sender", {})
|
|
chat_id = sender.get("id", "unknown")
|
|
|
|
return f"{account_id}:{chat_id}" |