Helcode | Хелкод | Скрипты и автоматизация
993 subscribers
52 photos
34 links
☎️ Контакты для связи: @helcodeadm
Download Telegram
multiprocessing или threading? Вопрос на миллион потоков... и процессов!

Ваш скрипт тормозит и вы хотите распараллелить все на свете.

🤔 Но что выбрать? Потоки? Процессы?

Ответ кроется в трех буквах — GIL (Global Interpreter Lock).

☕️ Это такой злой бариста в кофейне Python, который не дает нескольким потокам одновременно молоть зёрна (выполнять Python-код). Но у каждого процесса своя кофейня (и свой GIL)!

Код-пример (CPU-bound):
# Много вычислений -> multiprocessing
import multiprocessing
import math

def calculate_factorial(n):
return math.factorial(n)

if __name__ == '__main__':
numbers = [100000, 200000, 300000] * 5 # Тяжелая работа
with multiprocessing.Pool() as pool:
results = pool.map(calculate_factorial, numbers) # 🚀 Запуск на всех ядрах!


Код-пример (I/O-bound):
# Много ожидания -> threading
import threading
import requests

def check_site(url):
response = requests.get(url)
return response.status_code

urls = ['https://google.com', 'https://yandex.ru', ...] * 10
threads = []
for url in urls:
thread = threading.Thread(target=check_site, args=(url,))
thread.start()
threads.append(thread)

for thread in threads:
thread.join() # 🧵 Ждем все потоки


Выбор зависит от типа задачи. Не используйте потоки для вычислений — вы не получите прироста, а только накладные расходы. Не используйте процессы для простых HTTP-запросов — вы создадите слишком много тяжелых процессов.

А вы чаще сталкиваетесь с I/O или CPU-bound задачами? И какой ваш любимый способ паралеллить?

P.S. GIL — это не баг, это фича, которая не дает твоему коду сломать интерпретатор. Но иногда так хочется его пристрелить... (шучу, не шучу).


🌐 @helcode | #python
Вот простая шпаргалка:

🌐 @helcode
Ваши логи выглядят как поток сознания писателя-авангардиста? Пора навести порядок!

📖 Читать обычные текстовые логи, где вперемешку идут отладочные сообщения, ошибки и информационные записи, - это как искать иголку в стоге сена. А если нужно автоматически анализировать логи? На помощь приходят структурированные логи в формате JSON.

Используем встроенный модуль logging в Python, но с кастомным форматтером.

Настройка структурированного логирования:
import logging
import json
from datetime import datetime

class StructuredMessage:
def __init__(self, message, **kwargs):
self.message = message
self.kwargs = kwargs

def __str__(self):
# Создаем словарь с основным сообщением и дополнительными полями
log_data = {
'timestamp': datetime.utcnow().isoformat() + 'Z',
'level': logging.getLevelName(logging.getLogger().getEffectiveLevel()),
'message': self.message,
**self.kwargs # Добавляем все переданные ключевые аргументы
}
return json.dumps(log_data)

# Настраиваем логирование
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
# Не нужно форматировать, тк наши сообщения уже строки JSON
handler.setFormatter(logging.Formatter('%(message)s'))
logger.addHandler(handler)
logger.setLevel(logging.INFO)

# Использование
logger.info(StructuredMessage("User logged in", user_id=123, ip="192.168.1.1", success=True))
logger.error(StructuredMessage("DB connection failed", attempt=3, timeout=30))


Вместо неструктурированной строки мы получаем JSON-объект:
{"timestamp": "2023-10-26T10:30:15.123456Z", "level": "INFO", "message": "User logged in", "user_id": 123, "ip": "192.168.1.1", "success": true}


Преимущества:
- Легко парсить автоматизированными системами (ELK Stack, Loki, CloudWatch).
- Можно добавлять любые метаданные к каждому событию (user_id, request_id, execution_time).
- Упрощен поиск и фильтрация по конкретным полям.

Как вы справляетесь с анализом логов?

Переход на структурированные логи - это как перейти от расшифровки древних свитков к аккуратной Excel-таблице. Информация та же, а работать в разы удобнее.


🌐 @helcode | #python
👍3
Как заставить скрипты общаться друг с другом: не только HTTP

Ваши скрипты живут в вакууме и не общаются? Пора познакомить их друг с другом! 🤝

Часто одна автоматизированная задача должна запускать другую или передавать ей данные. Делать это через запись в файл и постоянный опрос - неэлегантно. Есть более эффективные способы межпроцессного взаимодействия (IPC).

👀 Рассмотрим несколько способов, кроме очевидного HTTP.

Способ 1: очереди сообщений (Message Queues) на примере Redis
# Скрипт-отправитель (producer.py)
import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)
task = {'user_id': 456, 'action': 'generate_report'}
r.lpush('task_queue', json.dumps(task)) # Кладем задачу в очередь


# Скрипт-получатель (consumer.py)
import redis
import json
import time

r = redis.Redis(host='localhost', port=6379, db=0)
while True:
# Блокирующее ожидание задачи из очереди (ждем 30 сек)
_, task_json = r.brpop('task_queue', timeout=30)
if task_json:
task = json.loads(task_json)
print(f"Обрабатываю задачу: {task}")
# ... обработка ...
time.sleep(1)


Способ 2: Named Pipes (именованные каналы) в Linux/macOS
# Создаем канал
mkfifo my_pipe

# Скрипт-читатель (зависнет, пока не появятся данные)
cat my_pipe

# Скрипт-писатель
echo "Hello from another script!" > my_pipe


* Очереди сообщений идеальны для построения распределенных систем. Гарантируют доставку, позволяют балансировать нагрузку между несколькими "воркерами".
* Именованные каналы - очень простой способ одноразовой передачи данных между процессами на одной машине. Работает на уровне файловой системы.

Как ваши скрипты общаются между собой?

Научить скрипты общаться - это как организовать работу отдела: можно кидать записки через стол (файлы), а можно настроить слаженный процесс с задачами и очередями. Второе - эффективнее.


🌐 @helcode | #python #bash
👍4
Тайм-ауты и повторные попытки: делаем ваши скрипты устойчивыми к сбоям

Ваш скрипт падает от малейшей ошибки сети? Пора научить его быть настойчивее!

В реальном мире сеть ненадежна, сервисы падают, а ответы задерживаются. Наивный скрипт, который не учитывает этого, обречен на частые failures. Устойчивость (resilience) - ключевое свойство для продакшн-автоматизации.

Паттерн "Retry with backoff" (Повтор с экспоненциальной задержкой).

Реализация на Python с помощью библиотеки tenacity:
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
import requests

@retry(
stop=stop_after_attempt(5), # Остановиться после 5 попыток
wait=wait_exponential(multiplier=1, min=2, max=30), # Экспоненциальная задержка: 2s, 4s, 8s... макс. 30s
retry=retry_if_exception_type(requests.exceptions.RequestException) # Повторять только при ошибках сети
)
def call_unreliable_api(url):
response = requests.get(url, timeout=3)
response.raise_for_status() # Выбросит исключение при HTTP-ошибке
return response.json()

# Использование
try:
data = call_unreliable_api("https://api.example.com/shaky-endpoint")
print("Успех!", data)
except Exception as e:
print(f"Не удалось после всех попыток: {e}")


wait_exponential: увеличивает задержку между попытками по экспоненте. Это вежливо по отношению к упавшему серверу (не DDoSим его) и дает ему время на восстановление.
stop_after_attempt: защита от бесконечных петель. Всегда должен быть лимит.
retry_if_exception_type: важно повторять только те ошибки, которые имеют смысл retry'ить (проблемы сети, тайм-ауты, 5xx ошибки сервера). Ошибку 404 (Not Found) retry'ить бессмысленно.

С какими сбоями чаще всего сталкиваются ваши скрипты?

Добавление retry-логики - это как дать скрипту несколько дополнительных жизней в видеоигре. Он может проиграть первый раунд, но в итоге все равно победит. 🎮


🌐 @helcode | #python
🤔2
Как избежать race condition: локи для идущих в ногу скриптов

🚪 Два скрипта заходят в одну папку... Звучит как начало плохой IT-шутки и большой проблемы!

Если один и тот же критический ресурс (файл, запись в БД, внешний API) могут одновременно использовать несколько экземпляров вашего скрипта - возникает состояние гонки (race condition). Результат может быть непредсказуемым: поврежденные данные, двойное списание средств, бессмысленная нагрузка.

Используем файловые блокировки (file locks). В Python для этого есть удобная библиотека filelock.

Пример: гарантируем, что только один экземпляр скрипта будет выполнять критическую операцию
from filelock import FileLock
import time

# Создаем lock-файл. Его наличие будет сигналом, что ресурс занят.
lock_path = "/tmp/my_script.lock"

# Используем менеджер контекста для гарантированного освобождения блокировки
with FileLock(lock_path, timeout=10): # Ждем 10 секунд, если lock занят
print("🔒 Lock acquired! Начинаю критическую операцию...")
# Здесь работа с общим ресурсом
time.sleep(5) # Имитация долгой работы
print(" Операция завершена. Lock released.")

# После выхода из блока 'with' блокировка автоматически снимается


➤ FileLock создает одноименный lock-файл. Попытка захватить lock, который уже у кого-то есть, будет блокировать выполнение (timeout) или вызовет исключение.
➤ Менеджер контекста (with) гарантирует, что блокировка будет снята даже если внутри блока произойдет ошибка.
➤ Это работает и между разными скриптами на разных языках, если они соблюдают одинаковый protocol (проверяют наличие одного и того же lock-файла).

В ваших скриптах есть критические секции? Как вы их защищаете?

Использование lock-файлов - это как повесить табличку «не беспокоить» на дверь офиса. Вежливо и предотвращает неловкие ситуации.


🌐 @helcode | #python
👍21
Парсим сайты, которые не хотят, чтобы их парсили: обход блокировок

Современные сайты защищаются от парсинга: капчи, блокировка по IP, анализ поведения браузера. Наивный requests.get() уже не работает. Нужно маскироваться под человека.

Используем Selenium WebDriver с Stealth-плагином и ротируем User-Agent.

Настройка "стелс"-браузера на Python:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium_stealth import stealth
import random

# Создаем опции Chrome
options = Options()
options.add_argument("--headless=new") # Запуск в фоне
options.add_argument(f"--user-agent={random.choice(user_agents)}") # Рандомный UA
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(options=options)

# Применяем stealth-плагин для сокрытия автоматизации
stealth(driver,
languages=["en-US", "en"],
vendor="Google Inc.",
platform="Win32",
webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine",
fix_hairline=True,
)

driver.get("https://hard-to-parse-site.com")
# Дальше работаем как с обычным браузером


➤ Ротация User-Agent: смена «отпечатка» браузера делает запросы менее похожими друг на друга.
➤ Selenium Stealth: плагин скрывает следы автоматизации, которые ищут анти-бот системы (например, наличие navigator.webdriver).
➤ HEADLESS-режим: запуск без GUI, но его одного часто недостаточно.

Важно: всегда проверяйте robots.txt и Terms of Service сайта. Уважайте нагрузку на чужой сервер (добавляйте задержки time.sleep()).

Приходилось ли вам бороться с анти-бот системами?

Писать парсер для защищенного сайта — это игра в кошки-мышки с системными администраторами этого сайта. Главное — не переходить в DDoS. 🐭🐱


🌐 @helcode | #python
Скрипты-самоубийцы: как автоматически остановить скрипт, если он сломался

Ваш скрипт завис и висит сутками, съедая ресурсы? Научите его вовремя уходить с достоинством!

Скрипты, которые работают с внешними ресурсами (сеть, БД, API), могут внезапно зависнуть на неопределенное время. Это съедает память, блокирует другие процессы и портит картину мониторинга. Нужен встроенный механизм самоликвидации.

Используем декораторы и сигналы для установки таймаутов.

Способ 1: таймаут на отдельную функцию (декоратор)
import signal
from functools import wraps

class TimeoutException(Exception):
pass

def timeout(seconds=10):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# Устанавливаем обработчик сигнала ALARM
def handle_timeout(signum, frame):
raise TimeoutException("Функция выполнена дольше {seconds} секунд!")

old_handler = signal.signal(signal.SIGALRM, handle_timeout)
signal.alarm(seconds) # Заводим будильник
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0) # Отключаем будильник
signal.signal(signal.SIGALRM, old_handler) # Восстанавливаем старый обработчик
return result
return wrapper
return decorator

# Использование
@timeout(5) # Максимум 5 секунд на выполнение
def call_slow_api():
import time
time.sleep(10) # Имитация долгого запроса
return "success"

try:
call_slow_api()
except TimeoutException:
print("Функция прервана по таймауту!")


➤ Сигнал SIGALRM: посылается ядром Linux по истечении времени, заданного signal.alarm().
➤ Декоратор @timeout: позволяет обернуть любую функцию, установив для нее лимит выполнения.
➤ Важно: этот метод работает только в главном потоке и не для всех операций (например, некоторые системные вызовы могут быть не прерваны).

Сталкивались ли вы с зависанием скриптов?


Научить скрипт самоликвидироваться — это как дать секретному агенту капсулу с ядом. Жестко, но эффективно для миссии.


🌐 @helcode | #python
👍2🤔1
Кэширование для ленивых: ускоряем скрипты в 100 раз без усилий

Ваш скрипт 100 раз ходит за одними и теми же данными? Пора дать ему память!

🏋️ Многие скрипты делают одни и те же «тяжелые» операции при каждом запуске: чтение больших файлов конфигурации, запросы к медленным API, сложные вычисления. Кэширование результатов между запусками — простой способ ускорить их в разы.

Используем декоратор @cache из стандартной библиотеки Python (появился в 3.9+).

Кэширование результатов тяжелой функции:
from functools import cache
import time

@cache # Волшебная строка, которая все кэширует
def get_weather(city):
# Имитация медленного HTTP-запроса к API погоды
time.sleep(2)
# Здесь реальный запрос: requests.get(f"http://weather.com/{city}").json()
return f"Погода в {city}: +25°C" # Возвращаем заглушку

# Первый вызов — медленный (2 секунды)
print(get_weather("Москва"))

# Все последующие вызовы с ТЕМ ЖЕ аргументом — мгновенные!
print(get_weather("Москва")) # Результат взят из кэша
print(get_weather("Москва")) # Снова из кэша

# Вызов с новым аргументом — снова медленный (2 секунды)
print(get_weather("Санкт-Петербург"))

# Кэш хранится ТОЛЬКО в течение работы программы.
# Для кэша между запусками нужны другие решения (redis, diskcache)


@cache (или @lru_cache из functools для более старых версий) запоминает аргументы, с которыми вызывалась функция, и ее возвращаемое значение.
➤ При повторном вызове с теми же аргументами функция не выполняется, а результат возвращается из памяти.
➤ Важно: aункция должна быть чистой (pure) - возвращать одинаковый результат для одинаковых аргументов без side effects.

Где вы используете кэширование?

Добавить @cache - это как поставить термос с кофе рядом с кроватью. Проснулся, выпил, уже бодрый - не надо идти на кухню и варить заново.


🌐 @helcode | #python
👍2🤔1
Мы переехали, обновились и снова в строю!

Бот @ScriptGeniusBot полностью функционирует в новой группе. Все скрипты на месте, поиск работает, категории доступны.

Что можно делать:
Искать нужные скрипты
Скачивать код одним файлом

Спасибо за терпение! Теперь работаем в усиленном режиме 💪

🌐 @helcode | #обновление #автоматизация
👍4
Как избежать хаоса: конфигурация скриптов в YAML

Ваши скрипты обрастают десятками параметров в коде? Пора вынести их в конфиг!

«Жесткие» параметры внутри кода (пути, адреса, пороги срабатывания) - это зло. При каждом изменении нужно лезть в код, рискуя что-то сломать. Правильное решение - выносить конфигурацию в отдельные файлы.

Используем YAML - человекочитаемый формат для конфигов.

Пример файла config.yaml:
database:
host: "localhost"
port: 5432
name: "my_app"
user: "admin"

logging:
level: "INFO"
file: "/var/log/my_app.log"

api:
endpoint: "https://api.example.com/v1"
timeout_seconds: 30
retry_attempts: 3

features:
enable_telemetry: false
cache_size: 1000


Загрузка конфига в Python:
import yaml  # pip install PyYAML

with open("config.yaml", "r") as f:
config = yaml.safe_load(f)

# Теперь доступ к параметрам прост и безопасен
db_host = config['database']['host']
timeout = config['api']['timeout_seconds']



➤ YAML поддерживает сложные структуры (словари, списки), комментарии и более читаем, чем JSON.
➤ Отделение кода от конфигурации - ключевая практика DevOps. Это позволяет использовать один и тот же код в разных окружениях (dev, prod) без изменений.
➤ Версионирование: rонфиг-файлы можно хранить в git отдельно от кода с разными ветками для разных сред.

Как вы храните конфигурацию?

Переход на YAML-конфиги - это как перейти от управления государством через указы, написанные на салфетке, к полноценной конституции. Порядок и предсказуемость!


🌐 @helcode | #yaml #python
👍2
Автоматическое тестирование скриптов: оно вам нужно?

Вы запускаете скрипт и молитесь, чтобы он не сломал прод? Пора подружиться с тестами!

Скрипты для автоматизации - такое же ПО, как и веб-сервисы. Они могут содержать баги, которые приводят к потере данных или простою систем. Писать тесты для скриптов кажется overkill, но это окупается их надежностью.

🛠 Пишем простой unit-тест для функции из скрипта с помощью pytest.

Допустим, у нас есть функция в script.py:
# script.py
def process_data(input_data):
"""Удаляет все числа меньше 10 из списка."""
if not isinstance(input_data, list):
raise ValueError("Input must be a list!")
return [x for x in input_data if x >= 10]


Пишем тест в файле test_script.py:
# test_script.py
import pytest
from script import process_data

# Стандартный тест на корректные данные
def test_process_data_positive():
assert process_data([1, 10, 20, 5]) == [10, 20]

# Тест на пограничное условие
def test_process_data_boundary():
assert process_data([9, 10]) == [10]

# Тест на некорректный ввод
def test_process_data_negative():
with pytest.raises(ValueError):
process_data("not a list")


Запуск тестов:
pytest -v test_script.py



➤ Unit-тесты проверяют отдельные функции («юниты») изолированно от остального кода.
pytest - стандарт де-факто для тестирования в Python: простой синтаксис, информативные сообщения об ошибках.
➤ Тесты помогают без страха рефакторить код и добавлять новую функциональность, не ломая старое.

Вы пишете тесты для своих скриптов автоматизации?

Писать тесты для скриптов — это как надевать страховку при работе на высоте. Кажется, что и так можно, но однажды это спасет вам проект.


🌐 @helcode | #python
👍2
Процесс, Поток, Демон: кто из них многозадачник, а кто – невидимка?

В мире Linux-автоматизации эти трое - основа основ. Путаница в них может стоить вам ресурсов сервера или нестабильной работы скрипта. Давайте расставим все по полочкам!

Теория:
➤ Процесс - это тяжеловес. Программа в работе со своим адресным пространством, памятью и данными. Как отдельный запущенный экземпляр браузера.
➤ Поток (Thread) - это легковес внутри процесса. У процессов могут быть свои «потоки-министры», которые делят между собой память и ресурсы родителя, но выполняют задачи параллельно. Экономят ресурсы, но усложняют дебаг.
➤ Демон (Daemon) - это процесс-отшельник. Он работает в фоне, не привязан к терминалу и обычно запускается при старте системы. Ваш веб-сервер (nginx) или cron - классические демоны.

Посмотреть все процессы можно классикой: ps aux. А чтобы найти демоны, ищите те, у которых в столбце TTY стоит ?.

А вы как предпочитаете писать многопоточные приложения? Python с threading, Go с горутинами, или старый добрый C? Поделитесь опытом в комментах!

Если процесс — это целый завод, то потоки — это цехи на этом заводе. А демон — это заводской призрак, который работает ночью, пока все спят.


🌐 @helcode | #linux
JQ: ваш карманный ниндзя для боя с JSON в терминале

Контекст: API сыпят на нас тоннами JSON. Ручной парсинг глазами — путь в никуда. Команда jq превращает эту кашу в структурированные данные, с которыми можно работать прямо в bash.

Код/Пример:
Допустим, у нас ответ от API такой: {"users": [{"name": "Alice", "id": 1}, {"name": "Bob", "id": 2}]}

➤ Достать всех юзеров: curl ... | jq '.users'
➤ Только имена: curl ... | jq '.users[].name' -> "Alice", "Bob"
➤ Имя первого юзера: curl ... | jq '.users[0].name' -> "Alice"
➤ Преобразовать в массив имен: curl ... | jq '[.users[].name]' -> ["Alice", "Bob"]

Ключ к успеху - точка (.) означает текущий объект, а комбинации фильтров [] (для массивов) и .key (для полей) творят "магию".

Какой ваш самый сложный или изящный jq-однострочник?

jq для JSON — это как световой меч для джедая: без него можно обойтись, но с ним ты чувствуешь силу.


🌐 @helcode | #python
xargs: или как заставить одну команду работать с тысячей аргументов

Вывод ls, find или grep часто нужно скормить другой команде (например, rm или mv). Но большинство утилит не принимают вход из пайпа. xargs — это мост между ними.

➤ Массовое удаление: find . -name "*.tmp" | xargs rm -f
(Найди все .tmp файлы и передай их имена команде rm)
➤ Параллельный запуск: cat urls.txt | xargs -P 5 -I {} curl -O {}
(-P 5 запустит 5 параллельных закачек curl)
➤ Для сложных имен (с переносами и пробелами): find . -name "*.log" -print0 | xargs -0 ls -la
(-print0 и -0 используют нулевой байт как разделитель — это безопасно)

xargs берет элементы из стандартного ввода, формирует из них аргументы и подставляет в указанную команду.

А вы используете xargs?


🌐 @helcode | #linux
👍5
Идемпотентность: почему ваш скрипт должен быть как кнопка лифта?

Представьте: Вы запускаете скрипт деплоя второй раз, потому что первый завис. А он вместо того, чтобы понять, что все уже готово, начинает все с начала и ломает систему. Знакомо? Этого избегают идемпотентные скрипты.

Идемпотентность — это свойство операции, позволяющее применять её многократно без изменения результата beyond the initial application. Проще: сколько бы раз вы не нажимали кнопку вызова лифта — он приедет только один раз.

Пример:
➤ НЕ идемпотентно: echo "data" >> file.log (при каждом запуске в файл добавится новая строка)
➤ Идемпотентно: echo "data" > file.log (файл будет перезаписан одним и тем же содержимым)
➤ Идемпотентно в Ansible: пакетные менеджеры (apt, yum) или модули копирования файлов по умолчанию идемпотентны. Они проверяют текущее состояние и меняют его только если нужно.

А вы задумываетесь об идемпотентности своих скриптов? Какие трюки используете (проверка флагов, lock-файлы)? Делитесь лайфхаками!

Идемпотентный скрипт — это как пес, который лает на почтальона каждый день с одинаковым энтузиазмом. Результат предсказуем.


🌐 @helcode
4🤔1
Grep: 5 флагов, которые вернут вам часы жизни

Ручной поиск по логам или коду — это адское занятие. grep — Ваш первый и главный друг в этой битве. Но знание всего пары флагов превращает его из молотка в целый "швейцарский нож".

🛠 Пример:
Допустим, ищем упоминания error в проекте:
-r (рекурсивно): grep -r "error" /path/to/project/ (обыщет все файлы во всех папках)
-i (игнорируй регистр): grep -i "connection" file.log (найдёт и Connection, и CONNECTION)
-c (покажи count): grep -c "404" access.log (не покажет строки, просто посчитает количество 404-ых ошибок)
-A, -B, -C (контекст):
1) grep -A 3 "Exception" log.txt (покажет строку с исключением и 3 строки после)
2) grep -B 2 "panic" log.txt (покажет строку с паникой и 2 строки до)
3) grep -C 1 "timeout" log.txt (покажет строку с таймаутом и по 1 строке до и после)

Флаги -A (After), -B (Before), -C (Context) — это спасение при чтении логов, где важно понять, что привело к ошибке и что было после.

Какой ваш самый частый или самый сумасшедший grep-однострочник?

Grep без этих флагов — это как искать иголку в стоге сена без магнита. А с ними — у Вас есть магнит, металлоискатель и карта, где спрятана вторая иголка.


🌐 @helcode | #linux
🤝61🔥1
Пишем на Python'е сторожа для важных задач

Запустили бэкап или сборку? Теперь можно пойти пить кофе и молиться, чтобы всё прошло well. Или написать простого бота-напоминалку, который отправит вам в Telegram сообщение о результате.

🛠 Пример:
1. Создаем бота у [@BotFather](https://t.me/BotFather), получаем TOKEN.
2. Узнаем ID чата: проще всего написать боту [@userinfobot](https://t.me/userinfobot), он его вам скажет.
3. Скрипт-напоминалка (notify.py):

import requests

TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID = "YOUR_CHAT_ID"
MESSAGE = " Бэкап успешно завершен! Можно спать спокойно."

url = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
params = {"chat_id": CHAT_ID, "text": MESSAGE}

requests.post(url, params=params).json()


4. Вставляем в скрипт бэкапа: python3 notify.py

Скрипт делает простой HTTP-запрос к Telegram API. Главное — не храните токен и chat_id в коде, если проект публичный! Используйте переменные окружения.

А вы куда получаете оповещения? Telegram, Slack, может быть, почта? И что мониторите? Расскажите о своем опыте автоматизации уведомлений!

Этот скрипт — как тот друг, который всегда звонит проверить, добрался ли ты домой. Надоедливо, но чертовски полезно.


🌐 @helcode | #python
👍2
Makefile: а этот парень зачем в нашем автоматизационном проекте?

✍️ Вы написали 10 скриптов для деплоя. Один чистит кэш, другой собирает проект, третий заливает его на сервер. Запускать их все по отдельности и запоминать порядок — не наш путь. Makefile — это ваш сборочный менеджер команд.

make — это утилита для управления сборкой, но программисты приспособили её для любой автоматизации. Вы описываете цели (targets) и зависимости между ними. Makefile делает процесс запуска сложных цепочек команд простым и предсказуемым.

🛠 Пример:

Вот простой Makefile для веб-проекта:
.PHONY: deploy clean build  # Говорим, что это не реальные файлы, а команды

build: clean
npm run build

clean:
rm -rf ./dist

deploy: build
scp -r ./dist/* user@server:/path/to/app

# Теперь можно просто запустить:
# make deploy
# и make сделает clean -> build -> deploy


А вы используете Makefile не по назначению? Для деплоя, тестов, Docker-команд?

Makefile — это как шпаргалка с командами для самого себя, которую ты сделал вчера, чтобы сегодняшний ты ничего не забыл. Забота о будущем себе. 😉


🌐 @helcode | #makefile
👍81
Коды HTTP: учим язык, на котором с нами разговаривают сервера

Ваш скрипт отправил запрос к API, а в ответ — тишина или ошибка. Чтобы не гадать на кофейной гуще, нужно знать базовые коды состояния HTTP. Это не роскошь, а необходимость для любого, кто работает с веб-автоматизацией.

Пример:
200 OK: всё хорошо, проходите. Запрос выполнен успешно.
201 Created: не просто "OK", а "Я только что создал новую сущность по твоей просьбе". Ответ на успешный POST-запрос.
400 Bad Request: "я тебя не понял". Сервер не смог разобрать запрос из-за неверного синтаксиса (например, невалидный JSON).
401 Unauthorized: "предъяви пропуск". Требуется аутентификация, а вы её не предоставили.
403 Forbidden: "у вас нет доступа". Пропуск есть, но в этот кабинет пройти нельзя.
404 Not Found: "здесь ничего нет". Ресурс не найден.
500 Internal Server Error: "у нас на сервере что-то сломалось, но мы не знаем что". Универсальная ошибка серверной части.
502 Bad Gateway: "проксируемый сервер отдал мне какую-то дичь". Частая ошибка в балансировщиках и прокся.

Коды 4xx — это ошибка клиента (Вашего скрипта). Коды 5xx — ошибка сервера (там, куда Вы стучитесь).

С какими самыми странными или редкими кодами вам приходилось сталкиваться?

Если API отвечает вам кодом 200 — это как получить в ответ "да, слушаю". Код 500 — это молчаливый вздох и закатывание глаз. А 404 — это просто "Иди нафиг".


🌐 @helcode | #http