Compare commits

...

38 Commits

Author SHA1 Message Date
Egor Matveev
5581786225 fix
All checks were successful
Deploy Prod / Build (pull_request) Successful in 25s
Deploy Prod / Push (pull_request) Successful in 11s
Deploy Prod / Deploy prod (pull_request) Successful in 10s
2025-07-17 23:27:52 +03:00
Egor Matveev
66b4348957 fix
All checks were successful
Deploy Prod / Build (pull_request) Successful in 5s
Deploy Prod / Push (pull_request) Successful in 9s
Deploy Prod / Deploy prod (pull_request) Successful in 11s
2025-06-15 17:24:52 +03:00
Egor Matveev
33901b0a82 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 5s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 17s
2025-06-15 17:13:54 +03:00
Egor Matveev
7b9d264ef9 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 8s
Deploy Dev / Push (pull_request) Successful in 10s
Deploy Dev / Deploy dev (pull_request) Successful in 12s
2025-06-15 17:08:15 +03:00
Egor Matveev
a707a8b93e fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 7s
Deploy Dev / Push (pull_request) Successful in 10s
Deploy Dev / Deploy dev (pull_request) Successful in 18s
2025-06-15 16:49:40 +03:00
Egor Matveev
df3354a536 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 7s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 17s
2025-06-15 16:45:51 +03:00
Egor Matveev
6a8f18300b fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 7s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 11s
2025-06-15 16:40:44 +03:00
Egor Matveev
b575ba5717 fix 2025-06-15 16:40:18 +03:00
Egor Matveev
24b1d39e10 fix 2025-06-15 16:39:33 +03:00
Egor Matveev
d61c665b6c fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 8s
Deploy Dev / Push (pull_request) Successful in 10s
Deploy Dev / Deploy dev (pull_request) Successful in 15s
2025-06-15 16:00:22 +03:00
Egor Matveev
4f0114e99a fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 12s
2025-06-15 14:53:13 +03:00
Egor Matveev
0cab3e52cb fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 5s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 12s
2025-06-15 14:45:14 +03:00
Egor Matveev
2d292dfc46 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 5s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 12s
2025-06-15 14:42:46 +03:00
Egor Matveev
72c5823ccd fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 5s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 15s
2025-06-15 14:40:14 +03:00
Egor Matveev
e0e7564fcc fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 12s
2025-06-15 05:27:31 +03:00
Egor Matveev
2bff8983b5 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 17s
2025-06-15 05:11:23 +03:00
Egor Matveev
4af857e2f3 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 5s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 12s
2025-06-15 05:07:16 +03:00
Egor Matveev
ef1d60e368 fix
All checks were successful
Deploy Prod / Build (pull_request) Successful in 5s
Deploy Prod / Push (pull_request) Successful in 8s
Deploy Prod / Deploy prod (pull_request) Successful in 12s
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Dev / Deploy dev (pull_request) Successful in 19s
2024-12-31 02:52:49 +03:00
Egor Matveev
8828bfd05b fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Dev / Deploy dev (pull_request) Successful in 9s
2024-12-31 02:49:03 +03:00
Egor Matveev
5a8d6c6488 fix
All checks were successful
Deploy Prod / Build (pull_request) Successful in 7s
Deploy Prod / Push (pull_request) Successful in 14s
Deploy Prod / Deploy prod (pull_request) Successful in 11s
2024-12-28 14:23:20 +03:00
Egor Matveev
f27122ce56 fix
All checks were successful
Deploy Prod / Build (pull_request) Successful in 7s
Deploy Prod / Push (pull_request) Successful in 8s
Deploy Prod / Deploy prod (pull_request) Successful in 10s
2024-12-28 14:18:34 +03:00
Egor Matveev
c509cb0b32 fix
All checks were successful
Deploy Prod / Build (pull_request) Successful in 24s
Deploy Prod / Push (pull_request) Successful in 17s
Deploy Prod / Deploy prod (pull_request) Successful in 19s
2024-12-28 13:49:39 +03:00
Administrator
0785997e6e fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 11s
Deploy Dev / Deploy dev (pull_request) Successful in 13s
Deploy Prod / Build (pull_request) Successful in 6s
Deploy Prod / Push (pull_request) Successful in 9s
Deploy Prod / Deploy prod (pull_request) Successful in 13s
2024-12-22 23:49:53 +03:00
Administrator
7742138ec8 fix
Some checks failed
Deploy Dev / Build (pull_request) Failing after 23s
Deploy Dev / Push (pull_request) Has been skipped
Deploy Dev / Deploy dev (pull_request) Has been skipped
2024-12-22 23:47:31 +03:00
Administrator
4d03af75d8 fix 2024-12-22 22:20:02 +03:00
Administrator
5a00dad803 add
All checks were successful
Deploy Dev / Build (pull_request) Successful in 24s
Deploy Dev / Push (pull_request) Successful in 21s
Deploy Dev / Deploy dev (pull_request) Successful in 33s
Deploy Prod / Build (pull_request) Successful in 11s
Deploy Prod / Push (pull_request) Successful in 19s
Deploy Prod / Deploy prod (pull_request) Successful in 22s
2024-12-21 19:27:00 +03:00
7ed7afbef4 fix
All checks were successful
Deploy Prod / Build (pull_request) Successful in 8s
Deploy Prod / Push (pull_request) Successful in 10s
Deploy Prod / Deploy prod (pull_request) Successful in 18s
2024-12-08 19:56:33 +03:00
73cc7b2c03 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 9s
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Dev / Deploy dev (pull_request) Successful in 11s
2024-12-08 19:42:19 +03:00
5dbacec1b0 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 8s
Deploy Dev / Push (pull_request) Successful in 10s
Deploy Dev / Deploy dev (pull_request) Successful in 13s
2024-12-08 19:40:13 +03:00
0b6dc3af1a fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 8s
Deploy Dev / Push (pull_request) Successful in 10s
Deploy Dev / Deploy dev (pull_request) Successful in 9s
2024-12-08 13:45:11 +03:00
98d69fff70 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 7s
Deploy Dev / Deploy dev (pull_request) Successful in 10s
2024-12-08 13:43:04 +03:00
0dbae621ab fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 9s
Deploy Dev / Push (pull_request) Successful in 7s
Deploy Dev / Deploy dev (pull_request) Successful in 11s
2024-12-08 12:05:54 +03:00
b4dd0a4b7b fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 7s
Deploy Dev / Push (pull_request) Successful in 10s
Deploy Dev / Deploy dev (pull_request) Successful in 10s
2024-12-08 11:48:41 +03:00
bb4c6d4748 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 5s
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Dev / Deploy dev (pull_request) Successful in 8s
2024-12-08 11:35:54 +03:00
92fe0c1999 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Dev / Deploy dev (pull_request) Successful in 12s
2024-12-08 11:34:08 +03:00
ec2c39ed35 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 7s
Deploy Dev / Deploy dev (pull_request) Successful in 11s
2024-12-08 11:26:07 +03:00
a4b580eab6 Merge branch 'master' of https://gitea.sprinthub.ru/self/botalka
All checks were successful
Deploy Dev / Build (pull_request) Successful in 32s
Deploy Dev / Push (pull_request) Successful in 14s
Deploy Dev / Deploy dev (pull_request) Successful in 10s
2024-12-08 11:21:47 +03:00
b3e44c4532 grpc 2024-12-08 11:20:54 +03:00
8 changed files with 67 additions and 79 deletions

View File

@@ -22,7 +22,6 @@ services:
networks: networks:
- configurator - configurator
- queues-development - queues-development
- locks-development
environment: environment:
STAGE: "development" STAGE: "development"
command: mailbox command: mailbox
@@ -39,5 +38,3 @@ networks:
external: true external: true
queues-development: queues-development:
external: true external: true
locks-development:
external: true

View File

@@ -22,7 +22,6 @@ services:
networks: networks:
- configurator - configurator
- queues - queues
- locks
environment: environment:
STAGE: "production" STAGE: "production"
command: mailbox command: mailbox
@@ -39,5 +38,3 @@ networks:
external: true external: true
queues: queues:
external: true external: true
locks:
external: true

3
.gitignore vendored
View File

@@ -119,3 +119,6 @@ GitHub.sublime-settings
.history .history
local_platform.json local_platform.json
*pb2*
schemas

View File

@@ -5,7 +5,6 @@ from telebot import apihelper
from daemons import base from daemons import base
from utils import platform from utils import platform
from utils import queues from utils import queues
from utils import locks
class Message(pydantic.BaseModel): class Message(pydantic.BaseModel):
@@ -23,9 +22,6 @@ class Daemon(base.Daemon, queues.TasksHandlerMixin):
def queue_name(self): def queue_name(self):
return 'botalka_mailbox' return 'botalka_mailbox'
def before_execute(self, task: dict):
locks.acquire(task['id'], 60)
def process(self, payload: dict): def process(self, payload: dict):
message = Message.model_validate(payload) message = Message.model_validate(payload)
bot = platform.platform_client.get_config('bots')[message.project][message.name] bot = platform.platform_client.get_config('bots')[message.project][message.name]

View File

@@ -1,6 +1,7 @@
import telebot import telebot
import threading import multiprocessing
import time import time
import json
from daemons import base from daemons import base
from utils import platform from utils import platform
@@ -9,45 +10,37 @@ from utils import queues
class Daemon(base.Daemon): class Daemon(base.Daemon):
def __init__(self): def __init__(self):
self.telegram_bots: dict[str, dict[str, telebot.TeleBot|None]] = {} self.processes: dict[str, multiprocessing.Process|None] = {}
self.threads: dict[str, dict[str, threading.Thread|None]] = {}
def execute(self): def execute(self):
while True: while True:
bots = platform.platform_client.get_config('bots') bots = platform.platform_client.get_config('bots')
for project_name, project in bots.items(): for project_name, project in bots.items():
if project_name not in self.telegram_bots:
self.telegram_bots[project_name] = {}
self.threads[project_name] = {}
for bot_name, bot_info in project.items(): for bot_name, bot_info in project.items():
if bot_name not in self.telegram_bots[project_name]: key = f'{project_name}_{bot_name}'
self.telegram_bots[project_name][bot_name] = None proc = self.processes.get(key)
self.threads[project_name][bot_name] = None
bot = self.telegram_bots[project_name][bot_name]
if bot_info.get('poll_enabled'): if bot_info.get('poll_enabled'):
if bot is not None and self.threads[project_name][bot_name].is_alive(): if proc and proc.is_alive():
print(f'process for {project_name} {bot_name} is alive') print(f'process for {project_name} {bot_name} is alive')
continue continue
print(f'starting process for {project_name} {bot_name}') print(f'starting process for {project_name} {bot_name}')
bot = telebot.TeleBot(bot_info['secrets']['telegram_token']) process = multiprocessing.Process(target=self.start_polling, args=(bot_info['secrets']['telegram_token'], bot_info['queue']))
thread = self.start_polling(bot, bot_info['queue']) process.start()
self.telegram_bots[project_name][bot_name] = bot self.processes[key] = process
self.threads[project_name][bot_name] = thread
print(f'started process for {project_name} {bot_name}') print(f'started process for {project_name} {bot_name}')
else: else:
if bot is None: if proc is None:
print(f'process for {project_name} {bot_name} is not alive') print(f'process for {project_name} {bot_name} is not alive')
continue continue
print(f'terminating process for {project_name} {bot_name}') print(f'terminating process for {project_name} {bot_name}')
bot.stop_bot() proc.terminate()
self.telegram_bots[project_name][bot_name] = None self.processes[key] = None
print(f'terminated process for {project_name} {bot_name}') print(f'terminated process for {project_name} {bot_name}')
time.sleep(10) time.sleep(10)
def start_polling(self, bot: telebot.TeleBot, queue: str) -> threading.Thread: def start_polling(self, token: str, queue: str):
bot = telebot.TeleBot(token)
@bot.message_handler(content_types=['audio', 'photo', 'voice', 'video', 'document', 'animation', 'text', 'location', 'contact', 'sticker', 'video_note']) @bot.message_handler(content_types=['audio', 'photo', 'voice', 'video', 'document', 'animation', 'text', 'location', 'contact', 'sticker', 'video_note'])
def do_action(message: telebot.types.Message): def do_action(message: telebot.types.Message):
queues.set_task(queue, message.json, 1) queues.set_task(queue, message.json, 1)
thread = threading.Thread(target=bot.polling) bot.polling()
thread.start()
return thread

View File

@@ -1,10 +1,10 @@
annotated-types==0.7.0 annotated-types==0.7.0
certifi==2024.8.30 certifi==2024.12.14
charset-normalizer==3.4.0 charset-normalizer==3.4.0
idna==3.10 idna==3.10
pydantic==2.10.2 pydantic==2.10.4
pydantic_core==2.27.1 pydantic_core==2.27.2
pyTelegramBotAPI==4.1.1 pyTelegramBotAPI==4.1.1
requests==2.32.3 requests==2.32.3
typing_extensions==4.12.2 typing_extensions==4.12.2
urllib3==2.2.3 urllib3==2.3.0

View File

@@ -1,27 +0,0 @@
import requests
LOCKS_URL = 'http://locks'
class Conflict(Exception):
pass
def acquire(name: str, ttl: int = 1):
resp = requests.post(f'{LOCKS_URL}/api/v1/acquire', json={
'name': name,
'ttl': ttl,
})
if resp.status_code == 409:
raise Conflict
if resp.status_code != 202:
raise Exception
def release(name: str):
resp = requests.post(f'{LOCKS_URL}/api/v1/release', json={
'name': name,
})
if resp.status_code != 202:
raise Exception

View File

@@ -1,4 +1,10 @@
from concurrent.futures import ThreadPoolExecutor
import datetime
import json
import os import os
import traceback
import uuid
import zoneinfo
import requests import requests
import time import time
@@ -15,32 +21,55 @@ class QueuesException(Exception):
class TasksHandlerMixin: class TasksHandlerMixin:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.executor = ThreadPoolExecutor(max_workers=1)
def _send_metric(self, start: datetime.datetime, end: datetime.datetime, success: bool):
def send():
requests.post(f'{QUEUES_URL}/api/v1/metric', json={
'service': 'botalka',
'queue': self.queue_name,
'success': success,
'timestamp': start.strftime("%Y-%m-%dT%H:%M:%S") + "Z",
"success": success,
"execution_time_ms": (end - start).microseconds // 1000,
"environment": stage,
})
self.executor.submit(send)
def poll(self): def poll(self):
while True: while True:
try:
response = requests.get(f'{QUEUES_URL}/api/v1/take', headers={'queue': self.queue_name}).json() response = requests.get(f'{QUEUES_URL}/api/v1/take', headers={'queue': self.queue_name}).json()
except requests.JSONDecodeError:
print('Unable to decode json')
time.sleep(3)
continue
task = response.get('task') task = response.get('task')
if not task: if not task:
time.sleep(0.2) time.sleep(0.2)
continue continue
start = datetime.datetime.now(zoneinfo.ZoneInfo("Europe/Moscow"))
try: try:
self.before_execute(task) print(f'process task with id {task["id"]}, attempt {task["attempt"]}')
self.process(task['payload']) self.process(task['payload'])
success = True
except Exception as exc: except Exception as exc:
print(f'Error processing message id={task["id"]}, payload={task["payload"]}, exc={exc}') print(f'Error processing message id={task["id"]}, payload={task["payload"]}, exc={exc}')
continue traceback.print_stack()
success = False
end = datetime.datetime.now(zoneinfo.ZoneInfo("Europe/Moscow"))
if success:
try: try:
resp = requests.post(f'{QUEUES_URL}/api/v1/finish', json={'id': task['id']}) resp = requests.post(f'{QUEUES_URL}/api/v1/finish', json={'id': task['id']})
if resp.status_code != 202: if resp.status_code != 202:
raise QueuesException raise QueuesException
self.after_execute(task) print(f'finish task with id {task["id"]}')
except: except:
print(f'Failed to finish task id={task["id"]}') print(f'Failed to finish task id={task["id"]}')
self._send_metric(start, end, success)
def before_execute(self, task: dict):
pass
def after_execute(self, task: dict):
pass
@property @property
def queue_name(self): def queue_name(self):