Я за сегодня сделала только 1 маленькую вещь: сделала в боте для генерации utm-меток обрезание всех параметров в исходной ссылке.
Да, у меня есть простой бот в телеграмме для smm-специалистов. Они отправляют боту голые ссылки, а бот им отвечает списками этих ссылок по соответствующими utm-метками для разных соц.сетей. Простая в реализации штука. Для нее нужно уметь работать с api телеграмм https://core.telegram.org/bots/api, также я использовала регулярные выражения для получения ссылки (https://regexr.com/3h8nh здесь можно найти готовые шаблоны и потестировать свои), для хранения и изменения списка меток использую табличку в виде csv-файла. Приложение крутится в AWS Lambda. Я его сделала за пару дней через пару месяцев изучения программирования. Это был уже не первый мой подобный проект.
В общем, в логах к моему приложению было обнаружено, что ребята присылают на вход ссылку с чужими utm-метками. Конечно, неправильно рубить все параметры url, так как там может быть что-то полезное, а стоило бы обрабатывать эту ситуацию с помощью условий, мягче, оставляя полезные параметры. Но, я знаю, что на проекте нет таких, поэтому не стала заморачиваться. Если вдруг понадобится обходить параметры, всегда можно доработать. А так, три строчки кода и проблема решена.
О таких нюансах можно не знать на старте, но при этом на самом деле не страшно запустить приложение с "проблемами", если им уже можно пользоваться и оно уже может решать какие-то задачи эффективнее.
Я что хочу сказать, даже простой функционал может упростить кому-то жизнь. Если вы только в начале пути разработчика, посмотрите вокруг себя, возможно вы можете улучшить жизнь себе и окружающим. В этом же и есть вся прелесть программирования.
Вот пример гайда как сделать простого бота на aws https://dev.to/nqcm/-building-a-telegram-bot-with-aws-api-gateway-and-aws-lambda-27fg
FYI вместо библиотеки requests я использовала встроенную urllib.request, что позволяет делать без дополнительных зависимостей.
https://github.com/mandrianova/telegram_bot а это мой первый проект, который я развиваю до сих пор, но уже на другом технологическом стеке и в рамках другого репозитория. В данном репозитории можно как раз подсмотреть логику работы с lambda. #Работа, #AWS
Да, у меня есть простой бот в телеграмме для smm-специалистов. Они отправляют боту голые ссылки, а бот им отвечает списками этих ссылок по соответствующими utm-метками для разных соц.сетей. Простая в реализации штука. Для нее нужно уметь работать с api телеграмм https://core.telegram.org/bots/api, также я использовала регулярные выражения для получения ссылки (https://regexr.com/3h8nh здесь можно найти готовые шаблоны и потестировать свои), для хранения и изменения списка меток использую табличку в виде csv-файла. Приложение крутится в AWS Lambda. Я его сделала за пару дней через пару месяцев изучения программирования. Это был уже не первый мой подобный проект.
В общем, в логах к моему приложению было обнаружено, что ребята присылают на вход ссылку с чужими utm-метками. Конечно, неправильно рубить все параметры url, так как там может быть что-то полезное, а стоило бы обрабатывать эту ситуацию с помощью условий, мягче, оставляя полезные параметры. Но, я знаю, что на проекте нет таких, поэтому не стала заморачиваться. Если вдруг понадобится обходить параметры, всегда можно доработать. А так, три строчки кода и проблема решена.
О таких нюансах можно не знать на старте, но при этом на самом деле не страшно запустить приложение с "проблемами", если им уже можно пользоваться и оно уже может решать какие-то задачи эффективнее.
Я что хочу сказать, даже простой функционал может упростить кому-то жизнь. Если вы только в начале пути разработчика, посмотрите вокруг себя, возможно вы можете улучшить жизнь себе и окружающим. В этом же и есть вся прелесть программирования.
Вот пример гайда как сделать простого бота на aws https://dev.to/nqcm/-building-a-telegram-bot-with-aws-api-gateway-and-aws-lambda-27fg
FYI вместо библиотеки requests я использовала встроенную urllib.request, что позволяет делать без дополнительных зависимостей.
https://github.com/mandrianova/telegram_bot а это мой первый проект, который я развиваю до сих пор, но уже на другом технологическом стеке и в рамках другого репозитория. В данном репозитории можно как раз подсмотреть логику работы с lambda. #Работа, #AWS
👍1🔥1
С каждой задачей я все больше начинаю понимать, меньше допускать примитивных ошибок, некоторые вещи перестают быть страшными.
Продолжаю использовать telethon в django. Сегодня делала функционал получения подписок и саму подписку на каналы.
Простые, казалось бы функции, но для меня стало открытием, что можно использовать with, чтобы создать подключение на время выполнения подписки и получения списка диалогов. Если что это это условно синхронные функции telethon, которые на самом деле также используют asyncio.
Кстати, под капотом create_client зашито создание отдельного event loop для клиента:
Теперь можно будет немного поправить функцию авторизации, так как теперь я знаю магию with.
Плюс заметила в логах, что я криво сделала сбор сообщений в каналах, так как на каждое сообщение я запрашивала информацию о чате с помощью бота телеграмма.
Переделала логику, стало немного лучше. Теперь я сначала проверяю наличие чата в своей бд.
Итого за сегодня:
- Примерно набросала в блокноте список функций для подписки
- Создала модель для хранения подписок и добавила ее в админку
- Сделала функцию получения списка подписок для клиента и собрала существующие подписки,
- Написала функцию для подписки и проверила ее, завтра по аналогии допишу функцию отписки
На завтра:
- Доделать логику подписки и отписки, сделать возможность управления через админку
- Автоматизировать подписки на новые каналы
- Выкатить новый функционал "на прод" #Работа
Продолжаю использовать telethon в django. Сегодня делала функционал получения подписок и саму подписку на каналы.
telegram_client = create_client(client.session)
with telegram_client:
dialogs = telegram_client.get_dialogs()
...
def subscribe(client: TelegramBotClient, channel: Channel):
telegram_client = create_client(client.session)
with telegram_client:
result = telegram_client(functions.channels.JoinChannelRequest(f"@{channel.username}"))
add_log("join channel", result)
Простые, казалось бы функции, но для меня стало открытием, что можно использовать with, чтобы создать подключение на время выполнения подписки и получения списка диалогов. Если что это это условно синхронные функции telethon, которые на самом деле также используют asyncio.
Кстати, под капотом create_client зашито создание отдельного event loop для клиента:
api_id = os.getenv('TG_API_ID')
api_hash = os.getenv('TG_API_HASH')
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
client = TelegramClient(StringSession(session), int(api_id), api_hash, loop=loop)
client.parse_mode = 'html' # <- Render things nicely
return client
Теперь можно будет немного поправить функцию авторизации, так как теперь я знаю магию with.
Плюс заметила в логах, что я криво сделала сбор сообщений в каналах, так как на каждое сообщение я запрашивала информацию о чате с помощью бота телеграмма.
Переделала логику, стало немного лучше. Теперь я сначала проверяю наличие чата в своей бд.
Итого за сегодня:
- Примерно набросала в блокноте список функций для подписки
- Создала модель для хранения подписок и добавила ее в админку
- Сделала функцию получения списка подписок для клиента и собрала существующие подписки,
- Написала функцию для подписки и проверила ее, завтра по аналогии допишу функцию отписки
На завтра:
- Доделать логику подписки и отписки, сделать возможность управления через админку
- Автоматизировать подписки на новые каналы
- Выкатить новый функционал "на прод" #Работа
Сегодня уж очень медленно работает подключение к aws. И вот, пока мои обновления пытаются выехать на мой условный прод, я напишу о сегодняшнем дне.
Мой план был доделать подписки и я их доделала. Осталось вот задеплоить.
Теперь можно подписываться и отписываться от каналов вручную и автоматически. Кстати, у телеграмма есть какое-то ограничение на количество подписок в какой-то период времени. После 30 каналов он выплюнул мне предупреждение во флуде и ограничил меня на 300 секунд. Поэтому придется как-то плавно обрабатывать всю ту массу каналов, на которые хочется подписаться.
Меня тут разговоры про ООП заставили задуматься о том, что я с безумной радостью почти весь код пишу функциями. Я подсмотрела в ютубе на канале Диджитализируй идею про то, что логику в Django стоит выносить в папку services, я ее создала и разразилась там в своих проектах на джанге множеством функций. Так вот, сегодня я сделала странную вещь. Не знаю на сколько это вообще легитимно (скорее всего не очень), но я в класс модели для телеграмм клиента перенесла все базовые функции для клиента (подключение, авторизацию, проверку логина, отправку кода, подписку, отписку). Это так удобно, хотя модель стала просто жутко жирной.
Еще один момент про telethon. Ранее я писала про открытие с with. Так вот, сегодня решила отрефакторить свою функцию авторизации и выяснила, что с with библиотека пытается стартануть клиент и требует авторизацию, если нет авторизованной сессии. Пришлось все неавторизованные функции оборачивать самостоятельно в connect и disconnect. Например:
- тяжелые миграции лучше делать отдельным файлом миграций. Создать ручную миграцию можно с помощью команды
Я их уже делала ранее для индексации текстов материалов для полнотекстового поиска. Я создала поле SearchVectorField и мне надо было его наполнить для старых материалов.
В этот раз я нашла на просторах интернета готовое решение по дедубликации материалов. Не очень красивое (очень некрасивое), но мне лень было придумывать самой:
Мой план был доделать подписки и я их доделала. Осталось вот задеплоить.
Теперь можно подписываться и отписываться от каналов вручную и автоматически. Кстати, у телеграмма есть какое-то ограничение на количество подписок в какой-то период времени. После 30 каналов он выплюнул мне предупреждение во флуде и ограничил меня на 300 секунд. Поэтому придется как-то плавно обрабатывать всю ту массу каналов, на которые хочется подписаться.
Меня тут разговоры про ООП заставили задуматься о том, что я с безумной радостью почти весь код пишу функциями. Я подсмотрела в ютубе на канале Диджитализируй идею про то, что логику в Django стоит выносить в папку services, я ее создала и разразилась там в своих проектах на джанге множеством функций. Так вот, сегодня я сделала странную вещь. Не знаю на сколько это вообще легитимно (скорее всего не очень), но я в класс модели для телеграмм клиента перенесла все базовые функции для клиента (подключение, авторизацию, проверку логина, отправку кода, подписку, отписку). Это так удобно, хотя модель стала просто жутко жирной.
Еще один момент про telethon. Ранее я писала про открытие с with. Так вот, сегодня решила отрефакторить свою функцию авторизации и выяснила, что с with библиотека пытается стартануть клиент и требует авторизацию, если нет авторизованной сессии. Пришлось все неавторизованные функции оборачивать самостоятельно в connect и disconnect. Например:
Пока пишу, приложение задеплоилось. Первый выкат прошел не очень, так как я накосячила с миграциями. Решила поправить один момент, сделать проверку на уникальность для связки двух полей в модели сообщений (message_id и chat). Так как в теории в базе могли возникнуть дубли, то в миграции добавила функцию по дедубликации. Так вот, извлекла урок:
client = self.client
client.connect()
sent = client.send_code_request(phone=self.phone)
add_log(f'sent code {self.phone}', str(sent), 1)
self.session = StringSession.save(client.session)
TelegramBotClient.objects.filter(id=self.id).update(session=self.session)
client.disconnect()
- тяжелые миграции лучше делать отдельным файлом миграций. Создать ручную миграцию можно с помощью команды
python manage.py makemigrations --empty yourappnameПро свои функции в миграциях можно почитать тут https://docs.djangoproject.com/en/3.1/ref/migration-operations/#runpython
Я их уже делала ранее для индексации текстов материалов для полнотекстового поиска. Я создала поле SearchVectorField и мне надо было его наполнить для старых материалов.
В этот раз я нашла на просторах интернета готовое решение по дедубликации материалов. Не очень красивое (очень некрасивое), но мне лень было придумывать самой:
Функция выполняется довольно долго, поэтому при деплое все пошло не так. В логах информации об ошибках не было, только заглянув в таблицу django_migrations я увидела, что моя миграция не прошла. Впрочем, просто сделав запрос в бд, я поняла, что на проде такая дедубликация мне бы и не понадобилась. В итоге я просто повторно выкатила приложение и на второй раз все завелось успешно. Единственное, что я сделала, это перенесла операцию по дедубликации в конец списка, хотя не думаю, что это имело какой-либо смысл. Со второго раза миграции выполнились. #Работа, #AWS, #Django
Entry = apps.get_model("telegram", "Message")
for row in Entry.objects.all().reverse():
if Entry.objects.filter(message_id=row.message_id, chat=row.chat).count() > 1:
row.delete()
Ура! Я за 1,5 месяца наконец-то перенесла весь изначальный функционал проекта полностью на сервер. То, что было сделано на коленке за несколько дней и запущено в виде простеньких скриптов на локальном компе, наконец-таки более ли менее оформлено в нормальную управляемую систему. А ведь изначально этим "сервисом" можно было управлять через файл конфига, а запуск проходил с помощью старта скрипта с бесконечным циклом.
Можно открывать шампанское и переходить к улучшению интерфейсов.
Следующий мой шаг - сделать управление через телеграмм бота, чтобы пользователям не нужно было заходить в админку. #Работа
Можно открывать шампанское и переходить к улучшению интерфейсов.
Следующий мой шаг - сделать управление через телеграмм бота, чтобы пользователям не нужно было заходить в админку. #Работа
Отгадываю загадки от api телеграмма.
По идее с помощью api бота можно получать информацию о публичных чатах и каналах по chat_id. Id чата может считаться либо цифры идентификатора, либо юзернейм с @. Сообщения по api клиента мне приходят с идентификатором канала. Я подумала, чтобы не напрягать клиент, буду я доставать всю нужную информацию о каналах с помощью бота. Это все присказка. Сказка вот в чем:
- Запрашиваю ботом инфу о канале с помощью идентификатора (метод getChat), получаю 400, канал не найден пишет мне телега
- Нахожу ручками юзернейм этого же канала, запрашиваю тем же ботом, но с помощью юзернейм, получаю нормальный ответ, id сходится.
- Повторно делаю первый запрос, ответ 200, все сходится.
Да что происходит то вообще??!! #Работа
По идее с помощью api бота можно получать информацию о публичных чатах и каналах по chat_id. Id чата может считаться либо цифры идентификатора, либо юзернейм с @. Сообщения по api клиента мне приходят с идентификатором канала. Я подумала, чтобы не напрягать клиент, буду я доставать всю нужную информацию о каналах с помощью бота. Это все присказка. Сказка вот в чем:
- Запрашиваю ботом инфу о канале с помощью идентификатора (метод getChat), получаю 400, канал не найден пишет мне телега
- Нахожу ручками юзернейм этого же канала, запрашиваю тем же ботом, но с помощью юзернейм, получаю нормальный ответ, id сходится.
- Повторно делаю первый запрос, ответ 200, все сходится.
Да что происходит то вообще??!! #Работа
Мда, а я хотела интерфейсами позаниматься. В итоге пришолсь искать вариант реализации для получения данных о новых каналах, как писала выше, api бота не справилось с этой задачей. Настроила в итоге методы get_chat() и forward.get_chat() для получения данных.
Выглядит это примерно так:
Есть подозрение, что телеграмм за частый запрос информации, может кинуть страйк за флуд. Но пока полет нормальный. Хотя мне не нравится то, как это получилось. Придется еще наводить порядок в этом функционале. А пока отлавливаю страйки и новые каналы.
И еще сегодня проснулись пользователи с новыми хотелками. Беклог подрос. Разработка - процесс бесконечный. #Работа
Выглядит это примерно так:
async def handler(event):
if hasattr(event.message.to_id, 'channel_id'):
info = await event.message.get_chat()
...
if event.message.fwd_from and event.message.fwd_from.channel_id:
info = await event.message.forward.get_chat()
...
Есть подозрение, что телеграмм за частый запрос информации, может кинуть страйк за флуд. Но пока полет нормальный. Хотя мне не нравится то, как это получилось. Придется еще наводить порядок в этом функционале. А пока отлавливаю страйки и новые каналы.
И еще сегодня проснулись пользователи с новыми хотелками. Беклог подрос. Разработка - процесс бесконечный. #Работа
Меня иногда спрашивают в личку, какой мой путь в программировании.
Обучение:
1. Когда-то давно (несколько лет назад) я проходила курс по основам программирования и кое-что пробовала делать на php и js. У меня даже остались конспекты.
2. Потом пробовала пройти курс джанго герлз, но ничего толком не поняла.
Опять же возвращаясь к питону, начала с джанги (курс по 1.9 типа https://youtu.be/-oQvMHpKkms), но мне посоветовали освоить сначала основы.
3. Дергалась по нескольким базовым курсам, пока не набрела на базовый курс "Полное руководство по Python 3: от новичка до специалиста" (https://www.udemy.com/course/bestpython/), который дал мне хорошую опорную точку. Прошла его за пару недель, буквально почти не вылезая из-за компа.
4. После него начинала курс по алгоритмам, но не прошла его до конца (надеюсь пройду позже) http://judge.mipt.ru/mipt_cs_on_python3/. Остановилась на 7 лекции.
5. Потом мне подкинули курсы cs50. Шикарные, сложные, интересные:
https://cs50.harvard.edu/x/2020/ - прошла полностью, получила сертификат
https://cs50.harvard.edu/web/2020/ - сдала половину проектов, прошла все теорию, потом пришлось переключиться на свои проекты.
Хочу когда-нибудь добраться до их курса по AI
6. Прошла курс по webpack и по docker (уже не помню ссылок), но добралась до того, что могу развернуть себе контейнеры. Основные проекты у меня сейчас на базе докера. Webpack пока почти не использовала.
7. Прошла полностью туториал Create a Twitter-like App with Python Django JavaScript and React. Full TUTORIAL https://youtu.be/f1R_bykXHGE, чтобы потрогать DRF и React. Ни одно, ни другое пока не использую в своих проектах, поэтому имею только поверхностное представление.
8. В планах пройти курс по JS + React. Пока он ждет.
Проекты:
1. У меня были какие-то попытки с php и js. Потом попытки поднять бложек на джанге, но все это было несерьезно.
2. Бот для местного сообщества. Я уже скидывала его первый репозиторий. https://github.com/mandrianova/telegram_bot
3. Проекты для cs50 web (https://github.com/mandrianova/Flack - чат на Flask, https://github.com/mandrianova/books - каталог книг на Flask, и немного верстки на Bootstrap)
4. Мелкие боты (для генерации utm, для оповещения о новых материалах на сайте)
5. Ну и самый мой большой мой проект - система для мониторинга сми, который я делаю последние пару месяцев.
Полноценным стартом изучения программирования считаю весну этого года. Все что было раньше, было несерьезно. #Учеба, #Жизнь, #Курсы
Обучение:
1. Когда-то давно (несколько лет назад) я проходила курс по основам программирования и кое-что пробовала делать на php и js. У меня даже остались конспекты.
2. Потом пробовала пройти курс джанго герлз, но ничего толком не поняла.
Опять же возвращаясь к питону, начала с джанги (курс по 1.9 типа https://youtu.be/-oQvMHpKkms), но мне посоветовали освоить сначала основы.
3. Дергалась по нескольким базовым курсам, пока не набрела на базовый курс "Полное руководство по Python 3: от новичка до специалиста" (https://www.udemy.com/course/bestpython/), который дал мне хорошую опорную точку. Прошла его за пару недель, буквально почти не вылезая из-за компа.
4. После него начинала курс по алгоритмам, но не прошла его до конца (надеюсь пройду позже) http://judge.mipt.ru/mipt_cs_on_python3/. Остановилась на 7 лекции.
5. Потом мне подкинули курсы cs50. Шикарные, сложные, интересные:
https://cs50.harvard.edu/x/2020/ - прошла полностью, получила сертификат
https://cs50.harvard.edu/web/2020/ - сдала половину проектов, прошла все теорию, потом пришлось переключиться на свои проекты.
Хочу когда-нибудь добраться до их курса по AI
6. Прошла курс по webpack и по docker (уже не помню ссылок), но добралась до того, что могу развернуть себе контейнеры. Основные проекты у меня сейчас на базе докера. Webpack пока почти не использовала.
7. Прошла полностью туториал Create a Twitter-like App with Python Django JavaScript and React. Full TUTORIAL https://youtu.be/f1R_bykXHGE, чтобы потрогать DRF и React. Ни одно, ни другое пока не использую в своих проектах, поэтому имею только поверхностное представление.
8. В планах пройти курс по JS + React. Пока он ждет.
Проекты:
1. У меня были какие-то попытки с php и js. Потом попытки поднять бложек на джанге, но все это было несерьезно.
2. Бот для местного сообщества. Я уже скидывала его первый репозиторий. https://github.com/mandrianova/telegram_bot
3. Проекты для cs50 web (https://github.com/mandrianova/Flack - чат на Flask, https://github.com/mandrianova/books - каталог книг на Flask, и немного верстки на Bootstrap)
4. Мелкие боты (для генерации utm, для оповещения о новых материалах на сайте)
5. Ну и самый мой большой мой проект - система для мониторинга сми, который я делаю последние пару месяцев.
Полноценным стартом изучения программирования считаю весну этого года. Все что было раньше, было несерьезно. #Учеба, #Жизнь, #Курсы
🔥2
А что вы сделали за сегодня? Я вот чутка добавила фильтров в админку, рассказала одному программисту про свой проект и смотрела коня боджека) А ведь хотела посмотреть что-нибудь из курсов. Хехе. Ну, и медитирую на цифры, которые стремительно растут... #Работа
ORM - прекрасная штука, Но сегодня я собирала данные о своей системе для презентации и поэтому пришлось немного пописать на сыром sql. Вот такие запросы у меня сегодня были:
У меня в системе уже больше 0,5 млн разных материалов. Из них около 442 500 собрано за последний месяц. При этом от публикации материала до доставки ее в соответствующую тему сейчас в среднем 73 секунды. Хехей! #Работа
Вот задачка-незадачка. В админке страница с ссылками на локальной машине загружается меньше, чем за секунду (данных всего в 2 раза меньше, чем на сервере), а на сервере за 16 секунд. С остальными страничками в админке такой проблемы не наблюдается.
Пойду запишу себе баг. Если есть идеи в чем может быть проблема - пишите в личку)
Сортировок нет, данных из других моделей на странице не запрашивается.
Есть подозрение, что проблема в самих данных, где-то что-то пошло не так, из-за этого тормозит. Но надо проверять. #Работа
Пойду запишу себе баг. Если есть идеи в чем может быть проблема - пишите в личку)
Сортировок нет, данных из других моделей на странице не запрашивается.
Есть подозрение, что проблема в самих данных, где-то что-то пошло не так, из-за этого тормозит. Но надо проверять. #Работа
Дневник разработчицы
Вот задачка-незадачка. В админке страница с ссылками на локальной машине загружается меньше, чем за секунду (данных всего в 2 раза меньше, чем на сервере), а на сервере за 16 секунд. С остальными страничками в админке такой проблемы не наблюдается. Пойду…
Сходила в бд, сделала просто select
```Вернулась на страницу, страница загрузилась за 1 секунду. Попробовала использовать поиск из админки, который работает как like, результат отдавался 15 секунд, что в принципе нормально, так как материалов много, а индексации самого текста нет. На тесте такой поиск отрабатывает за 3 секунды.
И что это было? #Работа
` select * from data_flow_link order by id desc limit 20;```Вернулась на страницу, страница загрузилась за 1 секунду. Попробовала использовать поиск из админки, который работает как like, результат отдавался 15 секунд, что в принципе нормально, так как материалов много, а индексации самого текста нет. На тесте такой поиск отрабатывает за 3 секунды.
И что это было? #Работа
Немного про инфру. Один мой друг посоветовал для отслеживания проблем очень интересный инструмент. Давно советовал, но я трусила вникать в новый инструмент. Все новое пугает, это ж надо разбираться.
https://newrelic.com/
Что я сделала, чтобы запустить его в итоге:
1. Зарегистрировалась. Дошла до документации по установке https://docs.newrelic.com/docs/agents/python-agent/installation/standard-python-agent-install, где при добавлении нового приложения, мне сервис выгрузил конфиг newrelic.ini (кнопка add python data)
2. Внесла в список установок newrelic, загрузила в проект файл из пункта 1. В докер файле все свои запуски обернула вот так
3. Пересобрала контейнер, запустила локально. Кликнула "See you data" и следующие кнопки на странице "Add your Python application data"
4. Бинго, получила данные.
5. Потом еще настроила окружения. В файле конфига можно найти настройки для разных окружений:
Чтобы они заработали, нужно добавить переменную окружения NEW_RELIC_ENVIRONMENT с указанием как раз названия типа окружения из конфига. Локально я отключила передачу данных, а вот на сервере установила переменной значение production.
6. Еще я попробовала обернуть asgi по примеру из документации https://docs.newrelic.com/docs/agents/python-agent/python-agent-api/asgiapplication-python-agent-api, но неудачно.
Добавила в asgi.py следующую строку
На что получила ошибку:
И джанга не смогла загрузиться. Надо разбираться. Вообще для этого инструмента много настроек. Еще интересно будет вывести логи. Но тут еще надо посмотреть, когда я вылезу за пределы бесплатного использования.
Кстати, https://t.me/lovely_it_hell канальчик друга, который мне посоветовал данный инструмент.
А ну, и результаты. С помощью инструмента заметила, что одна из rss-лент уж очень быстро отдает ответ. Посмотрела в ленту - свежие материалы в ней есть, а у меня их нет. Поняла, что зря я не передаю user-agent при запросе лент. Добавила, подтянулись новые материалы из нескольких лент. Посмотрим, что будет дальше, но теперь запросы отправляю с разными юзер-агентами. #Tools
https://newrelic.com/
Что я сделала, чтобы запустить его в итоге:
1. Зарегистрировалась. Дошла до документации по установке https://docs.newrelic.com/docs/agents/python-agent/installation/standard-python-agent-install, где при добавлении нового приложения, мне сервис выгрузил конфиг newrelic.ini (кнопка add python data)
2. Внесла в список установок newrelic, загрузила в проект файл из пункта 1. В докер файле все свои запуски обернула вот так
NEW_RELIC_CONFIG_FILE=newrelic.ini newrelic-admin run-program hypercorn monitoring_admin.asgi:application --bind 0.0.0.0:8000 --workers 3
3. Пересобрала контейнер, запустила локально. Кликнула "See you data" и следующие кнопки на странице "Add your Python application data"
4. Бинго, получила данные.
5. Потом еще настроила окружения. В файле конфига можно найти настройки для разных окружений:
monitor_mode = false
[newrelic:test]
monitor_mode = false
[newrelic:staging]
app_name = noctua (Staging)
monitor_mode = true
[newrelic:production]
monitor_mode = true
Чтобы они заработали, нужно добавить переменную окружения NEW_RELIC_ENVIRONMENT с указанием как раз названия типа окружения из конфига. Локально я отключила передачу данных, а вот на сервере установила переменной значение production.
6. Еще я попробовала обернуть asgi по примеру из документации https://docs.newrelic.com/docs/agents/python-agent/python-agent-api/asgiapplication-python-agent-api, но неудачно.
Добавила в asgi.py следующую строку
application = newrelic.agent.ASGIApplicationWrapper(application)
На что получила ошибку:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/hypercorn/asyncio/context.py", line 28, in _handle
await invoke_asgi(app, scope, receive, send)
File "/usr/local/lib/python3.8/site-packages/hypercorn/utils.py", line 214, in invoke_asgi
asgi_instance = app(scope)
File "/usr/local/lib/python3.8/site-packages/newrelic/api/asgi_application.py", line 329, in nr_asgi_wrapper
return nr_async_asgi(*_bind_receive_send(*args, **kwargs))
TypeError: _bind_receive_send() missing 2 required positional arguments: 'receive' and 'send'
И джанга не смогла загрузиться. Надо разбираться. Вообще для этого инструмента много настроек. Еще интересно будет вывести логи. Но тут еще надо посмотреть, когда я вылезу за пределы бесплатного использования.
Кстати, https://t.me/lovely_it_hell канальчик друга, который мне посоветовал данный инструмент.
А ну, и результаты. С помощью инструмента заметила, что одна из rss-лент уж очень быстро отдает ответ. Посмотрела в ленту - свежие материалы в ней есть, а у меня их нет. Поняла, что зря я не передаю user-agent при запросе лент. Добавила, подтянулись новые материалы из нескольких лент. Посмотрим, что будет дальше, но теперь запросы отправляю с разными юзер-агентами. #Tools
Нельзя просто так взять и запустить! Короче, я не смогла нормально подружить asgi с new relic, как я ни крутила, ничего нормально не завелось. В итоге, я плюнула и решила попробовать middleware. Про то что это и как этим пользоваться хорошо рассказано в видео https://youtu.be/Qe8YI5wXJng
Я просто обернула функции:
Название не придумала, поэтому как есть. Оно работает!
Обнаружила свою проблему с долгой загрузкой админки. Выяснилось, что проблема в запросе count(*) для всех объектов (по 8 секунд). Теперь придумываю как ее решать. #Tools
Я просто обернула функции:
newrelic.agent.initialize('newrelic.ini')
class FirstMiddleware:
@newrelic.agent.web_transaction()
def __init__(self, get_response):
self._get_response = get_response
@newrelic.agent.web_transaction()
def __call__(self, request):
response = self._get_response(request)
return response
Название не придумала, поэтому как есть. Оно работает!
Обнаружила свою проблему с долгой загрузкой админки. Выяснилось, что проблема в запросе count(*) для всех объектов (по 8 секунд). Теперь придумываю как ее решать. #Tools
Инфра, продолжение...
Заходишь в логи базы данных, а там каждую секунду неуспешные попытки авторизации. И это точно не ты:
У меня на этом инстансе висело 3 базы данных. Одну из которых использовала lambda. В общем, нельзя так просто взять и закрыть доступ от нехороших людей к бд, при этом оставив его для своей функции в лямбде. В этом весь AWS. Пришлось утягивать эту базу на отдельный инстанс на отдельном аккаунте (чтобы бесплатно, да). После чего я уже смогла закрыть лавочку для тех кул-хацкеров, что хотят меня ломануть. Подлецы! Зато aws классно подтягивает локальный ip, когда настраиваешь security group. Удобно.
Ну, и на всякий случай дефолтного пользователя для нового инстанса назвала сразу не postgres)
А и еще. Гуглила вчера весь вечер как решать проблему с count(), вот нет хорошего решения( Все костыли. Зато потыкала переопределение queryset и manager в джанге. В общем, тут описан вариант решения. Я его немного подкорректировала, потому что для постгрес там были явные ошибки. Не уверена, что у меня получилось на 100% верно. Выглядит как очень фу, на самом деле:
Заходишь в логи базы данных, а там каждую секунду неуспешные попытки авторизации. И это точно не ты:
2020-09-21 22:30:00 UTC:59.108.92.240(43526):postgres@postgres:[17605]:FATAL: password authentication failed for user "postgres"
2020-09-21 22:30:00 UTC:59.108.92.240(43527):postgres@postgres:[17649]:DETAIL: Password does not match for user "postgres".
Connection matched pg_hba.conf line 13: "host all all 0.0.0.0/0 md5"
У меня на этом инстансе висело 3 базы данных. Одну из которых использовала lambda. В общем, нельзя так просто взять и закрыть доступ от нехороших людей к бд, при этом оставив его для своей функции в лямбде. В этом весь AWS. Пришлось утягивать эту базу на отдельный инстанс на отдельном аккаунте (чтобы бесплатно, да). После чего я уже смогла закрыть лавочку для тех кул-хацкеров, что хотят меня ломануть. Подлецы! Зато aws классно подтягивает локальный ip, когда настраиваешь security group. Удобно.
Ну, и на всякий случай дефолтного пользователя для нового инстанса назвала сразу не postgres)
А и еще. Гуглила вчера весь вечер как решать проблему с count(), вот нет хорошего решения( Все костыли. Зато потыкала переопределение queryset и manager в джанге. В общем, тут описан вариант решения. Я его немного подкорректировала, потому что для постгрес там были явные ошибки. Не уверена, что у меня получилось на 100% верно. Выглядит как очень фу, на самом деле:
class ApproxCountPgQuerySet(models.query.QuerySet):
"""approximate unconstrained count(*) with reltuples from pg_class"""
def count(self):
if self._result_cache is not None and not self._iter:
return len(self._result_cache)
if hasattr(connections[self.db].client.connection, 'pg_version'):
query = self.query
if query.high_mark is None and query.low_mark == 0 and not any([
query.where,
query.select,
query.group_by,
hasattr(query, "having"),
query.distinct
]):
# If query has no constraints, we would be simply doing
# "SELECT COUNT(*) FROM foo". Monkey patch so the we get an approximation instead.
parts = [p.strip('"') for p in self.model._meta.db_table.split('.')]
cursor = connections[self.db].cursor()
if len(parts) == 1:
cursor.execute("select reltuples::bigint FROM pg_class WHERE relname = %s", parts)
else:
cursor.execute(
"select reltuples::bigint FROM pg_class c JOIN pg_namespace n on (c.relnamespace = n.oid) WHERE n.nspname = %s AND c.relname = %s",
parts)
return cursor.fetchall()[0][0]
return self.query.get_count(using=self.db)
Но пока это не критичная проблема, поэтому отложу ее на потом. #DjangoИнтерфейс... Все мои надежды на просто решение через тележку не сбылись. Я подступила к этой задаче, но осознала, что слишком много уже функционала и настроек, чтобы можно было легко и непринужденно сделать все через телеграмм.
В итоге я сегодня сделала еще одну маленькую фичу, а завтра пойду начинать проходить отложенный курс по JS, дабы сделать красивую и удобную админку.
Про кнопки в телеграмме.
Я пользуюсь api телеграмма без дополнительных библиотек. Сегодня добралась до реализации своей кнопки к отправленным сообщениям, чтобы удалять лишнее и помечать удаленное как ошибку.
Для этого в данные, отправляемые методом sendMessage я добавила:
json.dumps(), чтобы получился json-объект. Каждый ряд кнопок - отдельный список [] внутри основного списка для inline_keyboard.
callback_data - данные, которые телеграмм отправляет в систему при клике на кнопку в виде callback_query. На такой запрос можно "ответить" (ограничено время на ответ) с помощью метода answerCallbackQuery. callback_query приходит со всеми данными о сообщении, для которого была нажата кнопка. Поэтому после получения запроса с кнопки я выполняю следующие действия:
1. Отправляю ответ "принято" с помощью метода answerCallbackQuery
2. Устанавливаю статус для данного сообщения в своей базе, что оно ошибочно.
3. С помощью метода deleteMessage и данных из callback_query удаляю ошибочное сообщение из чата.
Мои функции для работы с этими методами:
Задача готова и зарелижена. Ни дня без релиза) #Python, #Работа
В итоге я сегодня сделала еще одну маленькую фичу, а завтра пойду начинать проходить отложенный курс по JS, дабы сделать красивую и удобную админку.
Про кнопки в телеграмме.
Я пользуюсь api телеграмма без дополнительных библиотек. Сегодня добралась до реализации своей кнопки к отправленным сообщениям, чтобы удалять лишнее и помечать удаленное как ошибку.
Для этого в данные, отправляемые методом sendMessage я добавила:
[{"text": "Мимо!", "callback_data": f"mistake={material.id}"}]
]})
json.dumps(), чтобы получился json-объект. Каждый ряд кнопок - отдельный список [] внутри основного списка для inline_keyboard.
callback_data - данные, которые телеграмм отправляет в систему при клике на кнопку в виде callback_query. На такой запрос можно "ответить" (ограничено время на ответ) с помощью метода answerCallbackQuery. callback_query приходит со всеми данными о сообщении, для которого была нажата кнопка. Поэтому после получения запроса с кнопки я выполняю следующие действия:
1. Отправляю ответ "принято" с помощью метода answerCallbackQuery
2. Устанавливаю статус для данного сообщения в своей базе, что оно ошибочно.
3. С помощью метода deleteMessage и данных из callback_query удаляю ошибочное сообщение из чата.
Мои функции для работы с этими методами:
url = bot_url + "/answerCallbackQuery"
data = {
"callback_query_id": callback_query_id,
"text": text,
"show_alert": alert
}
response = post_request(url, data)
return response
def delete_message(chat_id, message_id):
url = bot_url + "/deleteMessage"
data = {
"chat_id": chat_id,
"message_id": message_id
}
response = post_request(url, data)
return response
Задача готова и зарелижена. Ни дня без релиза) #Python, #Работа
Инфра. Подключение SSL-сертификата. AWS Elastic Beanstalk
AWS продолжает меня заставлять изучать нюансы инфраструктуры. 2 дня я пыталась решить нехитрую задачку изменения конфигов для nginx для работы сертификата на моем домене.
Открываю документацию, делаю как написано - не работает. Перерываю кучу статей в интернете... Пробую... Не работает. Вручную через ssh запускаем - работает! Ну ладно...
Все варианты в документации и в статьях сводятся к команде files, которая в нужном месте создает нужный файл.
Пытаюсь через команды докера положить туда, куда надо файлы конфигов. Не работает.
Во всех случаях в нужном месте после деплоя файла просто нет. В логах никак не могу найти информацию почему.
Пытаюсь еще 100500 раз по-всякому сделать как написано в документации - не работает...
Нахожу НЕРАБОЧЕЕ решение на стаковерфлоу - положить конфиги в директорию .ebextensions/nginx. Конечно, он не работает. Но! внезапно, aws в ЛОГАХ подсказывает как можно:
Пробую... Работает!
Я нигде в документации не видела такого варианта.
Сами конфиги для nginx легко гуглятся, если что.
Блин, безумие и отвага. #AWS
AWS продолжает меня заставлять изучать нюансы инфраструктуры. 2 дня я пыталась решить нехитрую задачку изменения конфигов для nginx для работы сертификата на моем домене.
Открываю документацию, делаю как написано - не работает. Перерываю кучу статей в интернете... Пробую... Не работает. Вручную через ssh запускаем - работает! Ну ладно...
Все варианты в документации и в статьях сводятся к команде files, которая в нужном месте создает нужный файл.
Пытаюсь через команды докера положить туда, куда надо файлы конфигов. Не работает.
Во всех случаях в нужном месте после деплоя файла просто нет. В логах никак не могу найти информацию почему.
Пытаюсь еще 100500 раз по-всякому сделать как написано в документации - не работает...
Нахожу НЕРАБОЧЕЕ решение на стаковерфлоу - положить конфиги в директорию .ebextensions/nginx. Конечно, он не работает. Но! внезапно, aws в ЛОГАХ подсказывает как можно:
Instance deployment: Elastic Beanstalk ignored your '.ebextensions/nginx' configuration directory. To include these configuration files, move them to '.platform/nginx'.
Пробую... Работает!
Я нигде в документации не видела такого варианта.
Сами конфиги для nginx легко гуглятся, если что.
Блин, безумие и отвага. #AWS
🔥1