Helcode | Хелкод | Скрипты и автоматизация
993 subscribers
52 photos
34 links
☎️ Контакты для связи: @helcodeadm
Download Telegram
Анализ логов auditd: находим угрозы

1. Утилиты:
- Поиск по метке:

  sudo ausearch -k sudo_usage


- Отчёт по файлам:

  sudo aureport -f



2. Пример лога:
type=SYSCALL msg=audit(...): uid=0 comm="rm" key="file_deletion"


👉 Что было: пользователь с UID=0 запустил rm.

🌐 @helcode | #bash #логи #автоматизация
Твой Python-скрипт вырос и хочет отдельной команды в терминале. Как ему это организовать? ☕️

Мы все начинаем с простого скрипта super_script.py. Но потом к нему добавляются аргументы, конфиги, логирование... И вот ты уже не запускаешь скрипт, а выполняешь сложный ритуал: python /path/to/script.py --verbose --output /home/user/data.json. Пора дать ему собственное имя и сделать полноценным CLI-инструментом!

Всё, что нужно, — это argparse из коробки Python. Смотрим, как превратить хаос в элегантную команду:

# file: data_processor.py
import argparse

def process_data(input_file, output_file, verbose=False):
# Здесь твоя магия обработки данных
if verbose:
print(f"Обрабатываем {input_file} и сохраняем в {output_file}")
return True

if __name__ == "__main__":
# Создаем парсер
parser = argparse.ArgumentParser(description='Крутой инструмент для обработки данных.')

# Добавляем аргументы
parser.add_argument('input', help='Путь до входного файла')
parser.add_argument('-o', '--output', required=True, help='Путь до выходного файла')
parser.add_argument('-v', '--verbose', action='store_true', help='Вербальный режим')

# Парсим аргументы
args = parser.parse_args()

# Передаем в функцию
process_data(args.input, args.output, args.verbose)


1. ArgumentParser — это наш главный конструктор команд.
2. add_argument определяет, какие флаги и аргументы мы принимаем. required=True для обязательных, action='store_true' для булевых флагов.
3. parse_args() превращает sys.argv в удобный объект с точками (args.input).

Следующий уровень: после этого можно установить скрипт как пакет через pip install -e . (прописав в setup.py) и твоя команда data_processor будет доступна из любой директории!

А какой у вас любимый инструмент для создания CLI? 🤔

P.S. Если твой скрипт после этого начнет требовать зарплату в виде GPU — мы не виноваты.


🌐 @helcode | #python
👍2🤔1
Скрипт для автоматического бэкапа MySQL

Ручные бэкапы — это как ходить по канату без страховки. Автоматизируем!

👩‍🔬 Решение:
#!/bin/bash  
BACKUP_DIR="/backups/mysql"
DATE=$(date +%Y%m%d)
mysqldump -u user -p"password" db_name | gzip > "$BACKUP_DIR/db_name_$DATE.sql.gz"

# Проверяем успешность и шлём алерт
if [ $? -eq 0 ]; then
echo "Backup OK" | sendmail admin@example.com
else
echo "Backup FAILED!" | sendmail admin@example.com
fi



🔧 Дополнения:
- Добавьте find $BACKUP_DIR -type f -mtime +30 -delete для удаления старых бэкапов.
- Используйте cron для запуска по расписанию.

Как вы организуете бэкапы? Храните на облаке или локально?

🌐 @helcode | #bash
👍1
Почему && лучше, чем ;?

command1; command2 выполнит обе команды, даже если первая упала. && — только если первая успешна.

🛠 Пример:
cd /nonexistent_dir && rm -rf *  # Удаление не сработает (и это хорошо!)  



Где ещё полезно:
- make && make test — не запускать тесты, если сборка провалилась.
- git pull && npm install — не ставить зависимости, если обновление репы не удалось.

Какие ещё операторы в Bash вы часто используете?

Использовать ; вместо && — это как прыгать с парашютом, не проверив, есть ли он за спиной.


🌐 @helcode | #bash
Как заставить старый скрипт работать в 10 раз быстрее

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

👁‍🗨 Мы все их видели: скрипты, написанные на коленке, которые со временем стали критически важными. Они работают, но отжирают уйму времени и ресурсов. Часто проблема не в сложности задачи, а в неоптимальных подходах.

👉Взгляните на этот кусок кода. Часто проблема в циклах внутри циклов, где можно применить списковые включения или функции из itertools.

Было (медленно):

results = []
for item in huge_list:
if some_condition(item):
for subitem in item.subitems:
if another_condition(subitem):
results.append(process(subitem))


Стало (быстро):

results = [process(subitem) for item in huge_list if some_condition(item) for subitem in item.subitems if another_condition(subitem)]
# Или еще лучше: использовать генератор для экономии памяти!
results_gen = (process(subitem) for item in huge_list ... )


Списковые включения в Python оптимизированы на уровне C и работают значительно быстрее классических for`-циклов с .append()`. А использование генераторов (`()`) вместо списков (`[]`) позволяет не загружать все данные в память сразу, что еще ускоряет работу с большими объемами данных.

А вы как ускоряли своих "динозавров"? Поделитесь самым крутым оптимизационным хаком в комментариях!

Это как в «Форсаже»: иногда не нужен новый двигатель, а нужно просто правильно настроить карбюратор и сбросить лишний вес.


🌐 @helcode | #python
👍3
Как автоматически генерировать сложные пароли для всей команды

Ваш пароль "qwerty123" прекрасен... если вы хотите подарить хакеру новый автомобиль. Давайте генерировать лучше!

Слабые пароли - главная дыра в безопасности. А придумывать и хранить десятки сложных паролей для разных сервисов не может даже человек с памятью как у Шерлока. Доверьте это машине.

Однострочник на Python в помощь всей команде:
import secrets
import string

alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
password = ''.join(secrets.choice(alphabet) for i in range(16))
print(password) # Пример: 'xT5&!k8@qL9#vR2$'


Мы используем модуль secrets, который криптографически безопасен (в отличие от random). string.ascii_letters + string.digits - это наш алфавит (буквы и цифры). Добавляем спецсимволы для сложности. Длина 16 символов - отличный старт.

А как вы управляете паролями в своей команде?

🌐 @helcode | #python
👍2
Автоматизируйте свои чат-боты: хватит отвечать на одни и те же вопросы!

Ваша команда снова спрашивает, «каой пароль от тестовой БД?».

🤖Пора научить бота делать вашу работу за вас.

В любой команде есть рутинные вопросы, которые отвлекают от работы. «Где документация?», «Как запустить проект?», «Кто дежурный?». Вместо того чтобы в сотый раз копировать один и тот же ответ, можно написать простого бота для Telegram или Slack.

Вот пример на Python с библиотекой python-telegram-bot для обработки частого вопроса.
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes

async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
# Бот отвечает на сообщение с ключевым словом
await update.message.reply_text(
"Коллега, привет! Вот частые ответы:\n"
"• Пароль от БД: 'supersecret'\n"
"• Документация: https://wiki.our-company.com/\n"
"• Как запустить: см. файл README.md в корне проекта"
)

if __name__ == '__main__':
app = Application.builder().token("YOUR_TOKEN").build()г
app.add_handler(MessageHandler(filters.TEXT & filters.Regex(r'(?i)(пароль|документация|как запустить)'), help_command))
app.run_polling()


Мы используем MessageHandler с фильтром filters.Regex(). Он ловит любое текстовое сообщение, в котором есть слова «пароль», «документация» или «как запустить» (регистр неважен благодаря `(?i)`), и автоматически отвечает заготовленным текстом.

Какой самый частый и раздражающий вопрос вы получаете в чате?

Это как поставить на частый вопрос автоответчик «я в отпуске», только Вы не в отпуске, а просто пьете кофе, пока бот работает.


🌐 @helcode | #python
👍2
Хватит хардкодить пароли в скриптах! Где и как хранить секреты

password = "12345" 
в коде — это как оставить ключи от квартиры в двери.

API-токены, пароли от БД, ключи шифрования. Они не должны лежать в открытом виде в коде, который вы заливаете на GitHub. Но как тогда скрипт получит к ним доступ? Решение есть.

Используем переменные окружения и файлы.

Способ 1: переменные окружения (просто и достаточно для многих случаев)

Задаем переменную в сессии или в файле ~/.bashrc / ~/.zshrc:export

DB_PASSWORD="my_super_secret_password_123"


И используем в Python-скрипте:

import os
db_pass = os.environ.get('DB_PASSWORD')
if not db_pass:
raise ValueError("Не задан пароль от БД!")


Способ 2: Файлы с секретами (более безопасно)

Создаем файл, который не будет попадать в git:

# .env file (добавляем в .gitignore!)
DB_HOST=localhost
DB_USER=admin
DB_PASSWORD=secret

Читаем его в коде с помощью библиотеки python-dotenv:

pip install python-dotenv
from dotenv import load_dotenv
load_dotenv() # Загружает переменные из файла .env в os.environ
db_pass = os.getenv('DB_PASSWORD')

Немного теории:

- Переменные окружения — это изолированное пространство памяти процесса. Их не видно в списке запущенных процессов (в отличие от аргументов командной строки).
- .env файлы — это удобный способ локальной разработки. На продакшене (сервере) эти же переменные задаются через конфигурацию systemd, Docker или панели управления хостингом.


Где вы храните свои секреты?
Признавайтесь, мы не осудим


Хардкодить пароль в коде — это как написать пин-код от карты на ней же шариковой ручкой. Удобно, но недальновидно.


🌐 @helcode | #bash #python
👍3🤣1
Автоматическое создание алиасов для часто ошибающихся команд

git comit? git pusht? Пора остановить это безумие!

Наша память избирательна, особенно в 3 часа ночи, когда деплой горит. Постоянно печатать git stauts вместо git status - это не про вас, это про всех. Зачем мучиться, если можно научить shell подстраховываться?

Просто добавьте эти строки в ваш ~/.bashrc или ~/.zshrc:

# Исправляем опечатки в git
alias git='() { if [[ $1 == "comit" ]]; then shift; command git commit "$@"; elif [[ $1 == "pusht" ]]; then shift; command git push "$@"; else command git "$@"; fi; }'

# Или универсальный солдат для частых опечаток:
alias comit='git commit'
alias pusht='git push'
alias gs='git status' # для ленивых, пользуюсь


Алиасы — это пользовательские сокращения или замены для длинных команд. Shell просто подставляет нужную строку вместо короткого алиаса. Это самый простой способ сэкономить нервы и количество нажатий на клавиатуру.

Какой ваш самый частый ляп в консоли?

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


🌐 @helcode | #bash
👍1
Как парсить PDF без специализированных библиотек

Парсить PDF на чистом Python — это как есть суп вилкой. Но иногда это бывает нужно...

PyPDF2, pdfminer, tabula — все это круто, пока Вам нельзя ставить лишние зависимости в проект или пока вам нужен лишь клочок текста из простого PDF. Иногда задача настолько мала, что тащить за собой библиотеку — это overkill.

Многие простые PDF можно "выстрелить" стандартными утилитами и регулярками.

# Используем pdftotext (из пакета poppler-utils)
pdftotext my_document.pdf - | grep -i "искомый текст"

# На Python, читаем PDF как бинарник и ищем строку
import re

with open('file.pdf', 'rb') as f:
pdf_content = f.read()
# Ищем что-то похожее на текст (опасно, но для простых случаев работает)
text_match = re.search(b'(Hello World)', pdf_content)
if text_match:
print(text_match.group(1).decode('utf-8'))


PDF — это сложный формат, но часто текст внутри него хранится в открытом виде. Утилита pdftotext пытается его извлечь, а дальше мы можем работать с текстом как обычно. Внимание: это хак, а не решение для сложных PDF с таблицами и картинками!

Предупреждаю, этот метод такой же надежный, как построить мост из спагетти. Но для быстрого прототипа или личных задач — вполне пригоден!


🌐 @helcode | #bash
👍2🤔2
Ваши скрипты умеют принимать правильные решения? (Просто о условных операторах)

ifelseelif... Это не заклинание, это ваши спиннеры для кода! 🧙‍♂️

Любой скрипт, который делает что-то полезное, рано или поздно должен уметь выбирать. «Если сервер не ответил, попробовать еще раз», «Если файл большой, сжать его перед отправкой». Без условий код — просто линейный набор команд, как рецепт для робота.

Смотрите, как оживает ваш код с условиями.

Было (скрипт-зомби):
#!/bin/bash
echo "Начинаем деплой..."
curl http://my-server.com/deploy
echo "Готово." # Всегда "Готово", даже если сервер сгорел


Стало (скрипт-интеллектуал):
#!/bin/bash
echo "Начинаем деплой..."
if curl -f http://my-server.com/deploy; then
echo " Деплой успешен!"
else
echo " Ошибка деплоя! Сервер не ответил."
exit 1
fi


Код возврата любой команды (0 — успех, не 0 — ошибка) — это ключ к принятию решений. Конструкция if [ условие ]; then... проверяет этот код. Флаг -f  у curl как раз заставляет его возвращать ненулевой код при HTTP-ошибке (404, 500 и т.д.).

А вы проверяете успешность команд в своих скриптах?

Писать скрипты без условий — это как играть в шахматы, всегда ходя только пешкой на одну клетку. Можно, но зачем?


🌐 @helcode | #bash
👍4
Тайминги и блокировки: как избежать «снежного кома» в cron

🤔 Представьте: задача в cron -е запускается каждые 5 минут, но иногда выполняется 10. Что будет? Через час у вас будет 12 параллельных процессов, грузящих систему!

Это классическая проблема наложения задач.

Решения:

1. timeout: жестко ограничить время выполнения.
* * * * * timeout 300 /path/to/script.sh # Остановить через 5 минут

2. flock: поставить блокировку на файл, чтобы скрипт не запускался, если предыдущий экземпляр еще работает.
* * * * * /usr/bin/flock -n /tmp/myscript.lock /path/to/script.sh


Ключ -n означает «не ждать». Если скрипт уже работает — новый запуск просто проигнорируется. Идеально для защиты от дублирования!

🌐 @helcode | #linux #cron #automation #performance
3👎1🤔1
requirements.txt звонит из 2010-го и просит вернуть его. Чем заменить?

Все мы знаем и... немного ненавидим этот файл. requests==2.28.1, pandas~=1.5.0, aiohttp. А потом — «ой, а почему у меня не запускается?». Ручное управление версиями, хаос в зависимостях, вечные конфликты. Это как собирать мебель без инструкции, надеясь, что все винтики подойдут.

Встречаем pyproject.toml — новый стандарт, который заменил всё. Это единый файл конфигурации для сборки, зависимостей и метаданных вашего проекта. Больше никаких setup.py, requirements.txt, setup.cfg и MANIFEST.in!

👀 Вот как это выглядит:

# pyproject.toml
[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "my_awesome_tool"
version = "0.1.0"
dependencies = [
"requests>=2.28.1",
"pandas~=1.5.0", # Совместимость с версиями 1.5.0+
"aiohttp"
]

[project.optional-dependencies]
dev = ["pytest", "black", "flake8"] # Зависимости для разработки!


* [build-system]: Говорит pip, как собирать ваш пакет.
* [project]: Основные метаданные и обязательные зависимости.
* [project.optional-dependencies]: Группы зависимостей (например, для тестов, линтинга, docs). Установить их можно так: pip install .[dev]

Но это еще не всё! Для полного счастья используйте poetry или pdm — они не только управляют зависимостями, но и создают виртуальное окружение и блокируют версии в poetry.lock/pdm.lock, гарантируя идентичные окружения у всех разработчиков. Это уровень «профи».

А что используете вы для управления зависимостями? 🗳
1. Старая гвардия requirements.txt (работает и ладно!)
2.
pyproject.toml + pip (современно и по стандарту)
3. poetry / pdm (магия и комфорт)
4. Anaconda (для data science)
5. Свой метод? Делитесь в комментах!

P.S. Если ваш requirements.txt сейчас плачет в углу — не говорите, что это мы вас надоумили. Просто дайте ему почитать pyproject.toml, пусть постыдится.


🌐 @helcode | #toml
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