Открытый канал ID 70941834150135

Махровый fullstack

А у нас в канале:

- Бэкенд, фронтенд и случайные мысли - в произвольных сочетаниях.
- Иногда литература, иногда всё, что взбредёт в голову.

Постится как душе просится.

Освежает разум. Возможны побочные эффекты.

Запаски:
- https://vk.ru/ordo_code
- https://t.me/ordo_code

Каналов в рубрике
1 733
Место этого канала
№ 1 233
Открыть рубрику →
Каналов в рубрике
648
Место этого канала
№ 471
Открыть рубрику →
Открыть в MAX

Публикации за период

По реакциям

Поиск и вся лента — после бесплатной регистрации. Свои даты — по подписке; владелец канала видит их бесплатно. Сортировка по реакциям — по подписке. Зарегистрироваться

Загрузка…

Тысяча и одна ошибка

— Не будь как Шазерезада - экономь квоту —

TL;DR
Одна ошибка может случиться тысячу раз, но в Bugsnag достаточно сообщить о ней один раз за 15 минут.
Кто о чём, а вшивый о багах.

Подключил я намедни проект Laravel к Bugsnag для сбора ошибок в коде, дабы не проспать чего апокалиптического. Но апокалипсис устроил сам... 😈

Проект ворочает довольно приличными объёмами данных и в случае катаклизма Bugsnag быстро бы оброс репортами.

Сказано - сделано!

Буквально за ночь доступные квоты были израсходованы! Источник проблем оказался внешний, но лимиты от этого не увеличились. 🤔

Чтобы решить подобную проблему на будущее было решено немного притормозить отправку репортов.

Основные требования к решению:
— Единый механизм дросселирования для любых типов исключений;
— Легкое добавление нового типа репорта без изменения существующей логики;
— Возможность самостоятельно определять, какие ошибки считать одинаковыми;
— Единая точка настройки ограничений, без размазывания логики по всему проекту;
— Максимально использовать штатные возможности Laravel и избнжать вендорлок сервиса мониторинга;
— Ограничение частоты репортов не должно влиять на выполнение бизнес-логики или обработку самих исключений;

1. Готовим максимально простой интерфейс
interface ThrottledReport
{
public const int THROTTLE_MINUTES = 15;
public function throttleKey(): string;
public function throttleMinutes(): int;
}

Основная идея - это throttleKey. Именно он определяет, какие ошибки считать одинаковыми. А throttleMinutes - определяет на сколько притормозить отправку повторяющихся репортов.

2. Добавляем trait с реализацией таймера по умолчанию
trait HasReportThrottle
{
public function throttleMinutes(): int
{
return static::THROTTLE_MINUTES;
}
}


3. Далее подключаем обработку эксепшена в bootstrap
->withExceptions(function (Exceptions $exceptions): void {
$exceptions->throttle(function (Throwable $e) {
if ($e instanceof ThrottledReport) {
return Limit::perMinutes($e->throttleMinutes(), 1)
->by($e::class . ':' . $e->throttleKey());
}

return null; // остальные исключения без ограничений
});
})

Тут есть важный нюанс: троттлинг работает на уровне Laravel Exception Handler, поэтому подавленные репорты не попадут не только в Bugsnag, но и в стандартные логи приложения. Но для моего решения — это приемлемо.

И ещё момент — важно учесть, что лимит хранится в кэше, поэтому важно иметь настроенный механизм кэширования. Например, redis.

4. Создаём своё исключение
final class DoNotSpamException extends RuntimeException implements ThrottledReport
{
use HasReportThrottle;

public const int THROTTLE_MINUTES = 60;

public function throttleKey(): string
{
return 'my-unique-key-for-error';
}
}


5. И используем
report(new DoNotSpamException('Something went wrong'));

‼️ Но тут важно помнить — это решение уменьшает частоту сообщений об ошибках, а не частоту возникновения самих ошибок. О количестве и качестве ошибок заботимся сами! ☕️

#php #laravel #exception #throttling #backend #web #разработка
Просмотры: 3
Перейти в пост Открыть в MAX Сообщить о неточности
Территориальный конфликт: война за 172.19.0.0/16

— Когда контейнер ищет внешний сервер у себя под носом —

TL;DR

Разбираемся, куда пропадают пакеты, при чём тут маршрутизация и как закончить войну за IP-адреса.

Кто‑то скажет — сделал из мухи слона! Да у меня каждый день такие приключения! Но для меня получился интересный кейс, и я лучше зафиксирую его для потомков.

Случилось страшное – из docker-контейнера недоступен удалённый хост. При этом с хост-машины никаких проблем с доступность нет – что надо пингуется, что пингуется, то роутится. Хост для определённости - 172.19.10.50.

WTF?!

Диагностика. Раунд первый

Для начала проверяем подсети, которые создал docker:


docker network inspect $(docker network ls -q) \
--format '{{.Name}}: {{range .IPAM.Config}}{{.Subnet}} {{end}}'

В моём случае обнаружились:


bridge: 172.17.0.0/16
traefik: 172.19.0.0/16
app-backend: 172.23.0.0/16
app-notifications: 172.29.0.0/16

В целом, картина уже ясна – видим пересечение сетей docker и внешнего хоста.

Для пущей убедительности проверяем маршрут в сетевом пространстве docker:


docker run --rm --network host \
nicolaka/netshoot \
ip route get 172.19.10.50

Бинго!


172.19.10.50 dev br-caf585119744 src 172.19.0.1

Cреда docker считает, что внешний сервер находится непосредственно в локальной сети.

Первое лечение. Неудачное

Перенёс сеть traefik в другой диапазон – 10.250.10.0/24, предварительно убедившись, что подсеть не используется где-то ещё.


networks:
traefik:
name: traefik
driver: bridge
ipam:
config:
- subnet: 10.250.10.0/24

Тут надо сказать, что app-backend и app-notifications используют общие external-сети. Поэтому сети создавались отдельно, а не средствами docker compose.



docker network create app-backend
docker network create app-notifications

Остановил использующие сеть проекты, удалил старые сети, поднял сети заново.
И… внешний сервер снова недоступен.

WTF?!

Диагностика. Раунд второй

Смотрим подсети ещё раз:


traefik: 10.250.10.0/24
app-backend: 172.18.0.0/16
app-notifications: 172.19.0.0/16

Постоянству docker можно позавидовать – не отпускает подсеть 172.19.0.0/16.

Лечение. Теперь окончательное

После повторного конфликта стало понятно: доверять docker автоматическое распределение адресов конкретно в этом окружении — идея так себе.
И поэтому сети создаём с явным указанием подсетей:


docker network create \
--driver bridge \
--subnet 10.250.11.0/24 \
app-backend

docker network create \
--driver bridge \
--subnet 10.250.12.0/24 \
app-notifications

Проверяем итоговую адресацию:


docker network inspect traefik app-backend app-notifications \
--format '{{.Name}}: {{range .IPAM.Config}}{{.Subnet}}{{end}}'

Получаем:


traefik: 10.250.10.0/24
app-backend: 10.250.11.0/24
app-notifications: 10.250.12.0/24


Проверяем доступность внешнего сервера:


docker run --rm \
--network container:notifications-php \
nicolaka/netshoot \
ping -c 3 172.19.10.50

И вот теперь всё заработало как надо!
Для кого-то это база, а для меня кирпичик опыта!

Полезное открытие: nicolaka/netshoot

У минималистичных docker-образов, таких как alpine, debian:slim часто отсутствуют даже базовые сетевые утилиты: ping, curl, nslookup, ip. Когда возникает необходимость разобраться с сетевыми проблемами, то удобнее использовать образ nicolaka/netshoot с целым арсеналом сетевых инструментов.

Но самое интересное — возможность подключиться к сетевому пространству уже работающего контейнера:


docker run --rm -it \
  --network container:notifications-php \
  nicolaka/netshoot

Теперь мы находимся в отдельном диагностическом контейнере, но используем сетевые интерфейсы, IP-адреса и маршруты notifications-php.
При этом исходный контейнер не пересобирается, а после выхода диагностический контейнер автоматически удалится благодаря --rm.

Отличная DevOps-выручалочка. Крайне рекомендую.

#docker #dockercompose #networking #devops
Просмотры: 8
Перейти в пост Открыть в MAX Сообщить о неточности
Великий исход из Bitbucket
– 347 репозиториев. Нормальный человек бы удалил –

tl;dr

Как перенести 347 репозиториев и не сойти с ума. Чудеса автоматизации с go, api и git –mirror

А помните в году так в 2023 пронеслась новость - Bitbucket заблокировал репозитории для разработчиков из России? Ох и испугался же я - ибо все существующие репозитории были на нём. Но делать нечего - взял и скачал все репозитории одним архивом на скорую руку в надежде в будущем перезалить куда-нибудь да и забросил его на антресоль.

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

Но тут что-то торкнуло заглянуть в аккаунт Atlassian.

А, Батюшки-святы! Аккаунт живой! Репозитории на месте! Дальше судьбу решил не искушать и таки перенести всё богатство.

Вооружившись Go, документацией к API и некоторым количеством терпения был создан скрипт, переносящий репозитории из Bitbucket -> GitFlic. Но получился небольшой миграционный конвейер.

Bitbucket API → git clone --mirror → GitFlic API → git push --mirror

Работает он в нескольких режимах: скачивание репозиториев и режим миграции.

По API Bitbucket скрипт получает полный список репозиториев с поддержкой постраничной загрузки и после чего каждый репозиторий клонируется локально.

Из интересного - git clone выполняется с флагом --mirror: создаётся bare-репозиторий, но без рабочей копии, но с полной историей, ветками, тегами и остальными git-особенностями, что заодно уменьшает объём промежуточных данных на диске.

Далее проверяется наличие проекта в GitFlic и если он не найден - создаётся через API GitFlic, после чего локальное зеркало отправляется командой git push --mirror.

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

И так несколько сотен раз.

На этом можно было бы и закончить, но тут появился Андрей (Андрей, привет! 🍺), заставивший пошебуршать по проектам, а меня дополнительно обуяло любопытство - что же у меня скопилось за почти 20 лет работы.

Скопилось 347 уникальных репозиториев — разной степени паршивости и полезности, конечно же, но всё же.

Содержат 29 133 уникальных коммитов, из которых 12 199 моих.

И, естественно, что коммиты не все мои - командную разработку никто не отменял. Но так или иначе, к каждому проекту были приложены собственные руки, мозги и нервы.

По языкам получился такой расклад:

PHP -- 395 293
JavaScript -- 141 132
CSS / SCSS -- 70 766
HTML -- 14 387
Dart -- 6 037
TypeScript -- 5 731
Swift -- 2 945
Ruby -- 2 666
Kotlin -- 1 847
Vue -- 1 545
Python -- 1 540


Также были найдены археологические слои: C/C++, Objective-C, голый SQL с триггерами и функциями, Java и 112 файлов на Go.

С типами проектов всё довольно стандартно, как подытожил ИИ: технологический профиль портфеля преимущественно веб-ориентированный. А то мы не знали ;)

В итоге, несколько часов программирования и 20Гб архивов плавно переехали на новое, не подверженное политическим веяниям, безопасное хранилище, а на SSD освободилось 40Гб. Почему 40? А у меня, оказывается, два архива было. Для надёжности, наверняка, а не благодаря Альцгеймеру ;)

#git #bitbucket #gitflic #golang #автоматизация #миграция
Просмотры: 16
Перейти в пост Открыть в MAX Сообщить о неточности
ВКонтакте Телеграм Одноклассники
Избранное в datool.ru

Следите за каналом в личном кабинете

Зарегистрируйтесь в datool.ru, чтобы добавить канал «Махровый fullstack» в избранное и отслеживать его показатели.

Зарегистрироваться
Для владельцев каналов

Подтвердите свой канал

Войдите или зарегистрируйтесь в datool.ru, затем добавьте нашего бота в канал по инструкции в личном кабинете. После проверки владения замок исчезнет и вам станет доступно управление каналом.

Войти или зарегистрироваться

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти