JuniorDevOps Engineer > Контейнеры и доставка > Инженерные практики и взаимодействие с командами
Короткий ответ Сначала превращаю запрос «нужна база» в проверяемые требования: тип данных и движок, объём и рост, пиковая нагрузка, окружения, доступность, RPO/RTO, backup, безопасность, владелец, срок и бюджет. Как это работает подробнее Одинаковая формулировка может означать небольшой PostgreSQL для MVP или критичный кластер с репликами и строгим восстановлением. Без уточнений инженер либо переплатит за запас, либо создаст конфигурацию, которая не выдержит production. Нагрузка. Оценить RPS, число соединений, характер чтения и записи, объём сейчас и прогноз роста. Надёжность. Согласовать допустимый простой, потерю данных, частоту backup и проверку восстановления. Эксплуатация. Определить окружения, владельца данных, доступы, мониторинг, срок и бюджет. Что использовать на практике Чек-лист. Зафиксировать ответы в тикете и получить подтверждение команды разработки и владельца сервиса. Проверка. Сопоставить требования с классом инстанса, хранилищем, репликацией и прогнозной стоимостью. Минимальный старт. Для MV
backupcapacity-planning
SeniorPython Developer > Основы Python > Исключения и контекстные менеджеры
Короткий ответ Если новые специфичные классы становятся настоящими подклассами существующего DataError и возбуждаются вместо него (а не вместе с полной заменой типа в местах, где raise возбуждал ровно DataError), весь код потребителей, перехватывающий except DataError, продолжает работать без изменений благодаря полиморфизму исключений, а потребители, которым нужна более точная обработка, могут постепенно переходить на перехват конкретных подклассов — риск сохраняется там, где потребители делают более узкие и хрупкие проверки (например, type(exc) is DataError, сравнение типа без учёта наследования) или полагаются на текст сообщения ошибки. Как это работает подробнее Механизм перехвата исключений в Python проверяет принадлежность классу через isinstance, который учитывает всю цепочку наследования — поэтому except DataError: продолжит перехватывать ConnectionDataError(DataError) и ValidationDataError(DataError) ровно так же, как раньше перехватывал голый DataError, если структура наследования правильно построен
backward-compatibilityexceptions
MiddlePython Developer > Основы Python > Производительность базы данных
Короткий ответ Сначала получают план выполнения через EXPLAIN ANALYZE, чтобы увидеть, использует ли запрос индекс или делает полное сканирование таблицы, затем по результатам добавляют подходящий индекс, переписывают запрос или пересматривают постраничную выборку, вместо того чтобы оптимизировать вслепую. Как это работает подробнее EXPLAIN ANALYZE показывает реальный план и время выполнения каждого узла запроса в PostgreSQL; Seq Scan на большой таблице там, где ожидался Index Scan, обычно означает отсутствие подходящего индекса или то, что условие в WHERE не позволяет его использовать (например, функция поверх индексируемого столбца). Пример кода Что использовать на практике Практика. Типичные находки — отсутствие составного индекса под часто используемый фильтр+сортировку, OFFSET с большим значением при постраничной навигации (лучше заменить на keyset pagination по последнему ID/дате), неэффективный JOIN с большой промежуточной таблицей без фильтрации заранее. Подводные камни Риск. Добавляют индекс на каждый
indexespagination
SeniorPerformance Marketer > Google Ads > Приватность и измерение
Короткий ответ Нет технического решения, которое одновременно даёт максимальный комплаенс и максимальную полноту данных — нужно признать это как компромисс между юридическим риском и качеством маркетинговых данных и выстроить совместное (юристы + маркетинг + аналитика) обсуждение допустимого риска, а не решать вопрос только силами одной из сторон. Как это работает подробнее Любая настройка, которая снижает трение для пользователя при даче согласия (более мягкий UX баннера, менее заметные кнопки отказа) увеличивает долю согласившихся пользователей и, соответственно, полноту данных, но одновременно повышает юридический риск, если регулятор сочтёт такой UX манипулятивным (так называемый dark pattern); максимально консервативный подход снижает юридический риск, но резко сокращает долю данных, доступных для измерения и оптимизации. Что использовать на практике Практика. Практический путь — использовать Consent Mode (продвинутый режим) для частичного восстановления данных через моделирование даже при отказе от cook
complianceconsent
JuniorPython Developer > Основы Python > Основы Python
Короткий ответ Python сочетает оба подхода: исходный код компилируется в байткод, а виртуальная машина затем интерпретирует его. В основной реализации CPython этапы объединены, поэтому корректный ответ — «и то и другое». Как это работает подробнее Исполнение программы проходит в два этапа, поэтому у Python есть черты и компилируемых, и интерпретируемых языков. Компиляция в байткод. Исходный код из файлов .py переводится в промежуточное представление — байткод, который сохраняется в файлы .pyc. Интерпретация байткода. Виртуальная машина Python исполняет байткод, поэтому код можно запускать построчно, а ошибки типов и часть проблем обнаруживаются уже в рантайме. Реализации. CPython совмещает оба режима, а PyPy дополнительно использует JIT-компиляцию для ускорения выполнения. Что использовать на практике Запуск без компиляции. Отдельной команды компиляции нет: файл исполняется сразу, а байткод переиспользуется при повторных запусках. Кэш байткода. Файлы .pyc ускоряют повторные запуски, ведь компиляция выполняетс
bytecodecompiler
SeniorPython Developer > Основы Python > Архитектура веб-API
Короткий ответ Нужно разделить ответ на части с разной «свежестью» — редко меняющиеся данные кэшировать агрессивно (CDN/HTTP-кэш с TTL или ETag), часто меняющиеся данные (остатки, цены в реальном времени) либо не кэшировать вовсе, либо кэшировать на очень короткий TTL, либо вынести в отдельный некэшируемый эндпоинт/запрос на клиенте. Как это работает подробнее HTTP-кэширование (заголовки Cache-Control, ETag, Last-Modified) позволяет CDN или промежуточным прокси отдавать ответ без обращения к backend, резко снижая нагрузку, но вводит окно, в течение которого клиент может увидеть устаревшие данные (пока не истечёт TTL или не придёт инвалидция). Инвалидация кэша по событию (push-инвалидция при изменении данных) даёт более свежие данные, но требует дополнительной инфраструктуры и усложняет систему по сравнению с простым TTL. Агрессивное кэширование с большим TTL резко снижает нагрузку на backend и упрощает инфраструктуру, но увеличивает окно показа устаревших данных, что может быть неприемлемо для полей типа оста
cachinghttp
MiddleDevOps Engineer > Контейнеры и доставка > CI/CD и управление релизами
Короткий ответ ArgoCD продолжает считать Git источником истины: если включена автоматическая синхронизация (`automated sync`) с `selfHeal: true`, он автоматически откатит ручное изменение обратно к тому, что описано в репозитории; правильный способ внести изменение — сначала поправить манифест в Git и дождаться синхронизации, а не менять ресурс напрямую в кластере. Как это работает подробнее ArgoCD периодически (и по webhook) сравнивает фактическое состояние ресурсов в кластере с desired state из Git. Статус `OutOfSync` означает обнаруженное расхождение. С `selfHeal: true` расхождение исправляется автоматически в течение следующего цикла сверки; без `selfHeal` ресурс просто помечается как рассинхронизированный, пока кто-то не нажмёт Sync вручную или не исправит разницу. Пример кода Что использовать на практике На практике. ручные изменения прямо в кластере («kubectl edit в проде») — частая причина путаницы в GitOps-командах: инженер решает проблему «здесь и сейчас», а через несколько минут ArgoCD незаметно от
argocdartifacts
SeniorPython Developer > Основы Python > Архитектура веб-API
Короткий ответ Нужно использовать таймауты на каждый внешний вызов (а не ждать бесконечно), паттерн circuit breaker для временного отключения вызовов к стабильно отказывающему сервису, и явно решить для каждой интеграции — является ли она критичной для основного пути запроса (тогда отказ должен приводить к явной ошибке клиенту) или вспомогательной (тогда можно деградировать функциональность, но вернуть основной ответ). Как это работает подробнее Без явного таймаута один медленный внешний вызов может удерживать поток/корутину обработчика существенно дольше ожидаемого, что при достаточном количестве параллельных запросов приводит к исчерпанию пула соединений/потоков и деградации всего сервиса, а не только той функциональности, что зависит от медленного внешнего сервиса. Circuit breaker отслеживает долю неудачных вызовов к конкретному внешнему сервису и при превышении порога временно перестаёт пытаться его вызывать (сразу возвращая отказ или деградированный ответ), давая внешнему сервису время восстановиться и н
middlewarepython
SeniorPython Developer > Основы Python > Надёжность API
Короткий ответ Нужно сочетание нескольких механизмов: жёсткий timeout на каждый вызов, circuit breaker, быстро прекращающий попытки при устойчивом отказе, изоляция ресурсов (отдельный пул соединений/потоков на эту интеграцию, чтобы её деградация не исчерпывала общие ресурсы сервиса), и заранее определённое поведение fallback (деградированный ответ или честная ошибка) — конкретные параметры и выбор fallback зависят от критичности зависимости для основной функциональности сервиса. Как это работает подробнее без изоляции ресурсов (паттерн bulkhead) медленные вызовы к одному внешнему сервису могут занять все доступные потоки/соединения пула, из-за чего даже запросы, не связанные с этим внешним сервисом, начинают отказывать — это классический каскадный отказ. Circuit breaker, отслеживая долю/количество ошибок за окно времени, переходит в "открытое" состояние и быстро отказывает новым вызовам без реальной попытки, давая внешнему сервису время восстановиться и защищая собственные ресурсы от трат на заведомо обречённ
bulkheadcircuit-breaker
MiddleDevOps Engineer > Контейнеры и доставка > Скриптинг и автоматизация
Короткий ответ Нужно проектировать шаги так, чтобы для каждого из них было известно, как его откатить или безопасно повторить (идемпотентно), использовать trap для гарантированной очистки/отката при любом сбое, и там, где это возможно, делать потенциально опасные шаги (например, миграции схемы БД) обратимыми и отделёнными от шагов, которые сложно откатить. Как это работает подробнее trap 'cleanup' ERR EXIT в bash позволяет выполнить функцию очистки при любом выходе из скрипта, в том числе аварийном, что даёт шанс откатить уже выполненные шаги или хотя бы оповестить об их состоянии. Для шагов, которые физически нельзя откатить мгновенно (необратимая миграция схемы), стратегия обычно сдвигается в сторону предварительной валидации и поэтапного раскатывания (сначала на части трафика), а не "чистого" отката. Пример кода Что использовать на практике Рекомендация. хороший подход — логировать, какой шаг выполняется и завершён успешно (например, писать маркеры в файл состояния), чтобы при повторном запуске после сбоя
bashdeployment