Retry в Go автотестах: как перестать бояться flaky-тестов

Flaky-тесты в Go — неизбежны, но наивные ретраи делают только хуже. Разбираем, почему retry — это не цикл и как правильно реализовать повторный запуск автотестов.

Компилируемый, многопоточный язык программирования

Flaky-тесты в Go — неизбежны, но наивные ретраи делают только хуже. Разбираем, почему retry — это не цикл и как правильно реализовать повторный запуск автотестов.

В домашней инфраструктуре у меня крутится десяток сервисов: Grafana, Zabbix, n8n, Navidrome, ollama, БД, пара дашбордов и тестовых API. Каждый раз, когда нужно было выставить новый сервис наружу, я открывал дашборд Cloudflare и руками проходил один и тот же путь: создать туннель, прописать ingress‑правило, добавить DNS записи, настроить Zero Trust Access. Минут пятнадцать, если без ошибок. С ошибками — больше, потому что один неверно скопированный tunnel ID ломает всю цепочку и приходится откатывать вручную.
На какой‑то раз стало понятно, что это рутина, которую можно свернуть в одну команду. Так появился cfzt — CLI на Go, который сейчас умеет:
zt up grafana 3000
И через несколько секунд grafana.domain.com смотрит на localhost:3000 через Cloudflare Tunnel, с настроенным Zero Trust Access и systemd сервисом, который переживет ребут.

После моей первой статьи про Pulse я не ожидал, честно говоря, примерно ничего. Но к моему удивлению увидел реакцию: немного поддержки, немного критики, несколько советов по UX.
Эта статья про то, как один комментарий заставил меня задуматься о безопасности, утечках данных, о проведении аудита и изменению подхода к разработке своего небольшого мессенджера.

Тёмная сторона есть, наверное, у каждого языка. У Go она выражена слабее: язык структурный, понятный, неплохо защищён по умолчанию. Но это не индульгенция. Разберём, что такое уязвимость и откуда она берётся, пройдёмся по типичным классам проблем на живых примерах с продакшена, посмотрим на инструменты локального анализа кода и обсудим, как выстроить продуктивные отношения с командой безопасности.

У меня было полторы сотни кросс-языковых фикстур, все тесты зелёные, и я был уверен, что мой Go-порт Yjs байт-в-байт совместим с оригиналом. Потом сравнил байты напрямую с канонической реализацией, и они разъехались: семантика сходится идеально, а на проводе документ толще.
Юнит-тесты, roundtrip и даже конвергенц-тесты систематически пропускают баги совместимости, когда портируешь чужой бинарный формат на другой язык. Рабочий метод один: генерировать фикстуры из канона и требовать в CI побайтового совпадения в обе стороны.
Разбираю конвейер и три реальных бага из трёх своих портов (Yjs, Loro, Willow): документ в 12 раз толще канона, big-endian остров, который молча портил бы все float’ы при обмене, и дыра, через которую 9-байтный апдейт заказывал make() на 67 ТБ. Метод обобщается на любой «порт формата X на язык Y», CRDT тут просто материал.

В прошлый раз я писал про рекурсивную задачу мониторинга: кто мониторит монитор? Если Prometheus упал — вы не видите ничего, и самое коварное тут в том, что отвалившийся мониторинг внешне неотличим от идеальной стабильности. Та статья заканчивалась честно и немного грустно: чистого решения нет, есть только слои подстраховки и остаточный риск, с которым приходится жить.

Я обычный инженер-программист в банке. Вечерами, после работы и семьи, я начал эксперимент: смогу ли я один, с помощью нейросетей, сделать мессенджер таким, каким, как мне кажется, он должен быть? Не «убийцу Telegram» или кого-либо другого, а просто альтернативу - спокойное место для общения. Без шума, без бесконечных кружков, без ощущения, что ты должен читать каналы, на которые никогда не подписывался.
Знаете это чувство, когда подписки и личные чаты свалены в одну кучу? Да, папки есть, но эти вездесущие счётчики непрочитанного… они просто сводят с ума. Ты выходишь из канала, а тебя кто-то туда возвращает — и ты даже не понимаешь, как и кто это сделал.
Я хотел чёткого разделения контекстов: группы отдельно, контакты отдельно, скрытые диалоги — чтобы глаза отдыхали. И спокойного, мягкого интерфейса. Сидя целый день перед монитором, хочется смотреть на приятные цвета, плавные переходы, а не на очередной аляповатый дизайн.
В общем то немного покумекав, я подумал - если тебе что-то не нравится - сделай сам! И я начал делать.
Так родился Pulse.

Аккуратный Go-сервис на net/http с единственной ручкой /time. Обновляем одну библиотеку через go get, не трогая свой код. После рестарта в сервисе появляется ручка /__injected, которая отдаёт строки из памяти процесса. Мы её не регистрировали — а пакет, который это сделал, формально даже не используется.
Разбираю шаг за шагом, как такое возможно: модель зависимостей Go и коварство //indirect, тихий вход через init(), сканирование кучи и unsafe. Pointer для поиска ServeMux в работающем сервере. И, конечно, как от этого защищаться — от аудита зависимостей до seccomp и read-only ФС.
Весь код — в репозитории, «вредонос» написан в учебных целях. Запускать только в песочнице.

AI сделал нас быстрее, очень сильно быстрее, но у этого момента есть побочный эффект. Наверно многим, кто уже столкнулся в вайбкодингом в своих проектах, знакомо такое чувство когда радуешься от того, что фичи делаются быстро и потом в какой-то момент ты понимаешь, что система деградировала настолько, что новое впиливается все сложнее и сложнее, кол-во багов растет, тех долг накапливается и кажется, что проще все снести и переписать.

Частенько ли у вас возникает желание пойти в одну очень популярную песочницу ? Я думаю раз в пол года - год у многих возникает такое желание. И также часто возникает желание поставить парочку сотен модов…

Год назад доступ к зарубежным LLM из России превратился в квест. OpenAI и Anthropic не принимают российские карты и блокируют запросы по гео. Обходные пути — VPN, иностранная карта, прокладка через знакомых за рубежом — годятся для пет-проекта, но не для продакшена, где нужен стабильный аккаунт, предсказуемый счёт и возможность объяснить бухгалтерии, за что платим.
Мы сделали apiglue — шлюз, который закрывает эту боль: один OpenAI-совместимый endpoint, за которым прячутся десятки провайдеров, оплата рублёвой картой и баланс в рублях. А заодно — управляемый хостинг n8n, чтобы не только дёргать модели через API, но и собирать на них автоматизации без своего сервера.
Ниже — как это устроено внутри и какие решения оказались неочевидными. Без маркетинга: где замерили — пишу замеры, где спроектировали на запас — так и говорю.

Привет, Хабр. Я Полина, продакт и главный редактор медиа-платформы «Своё Вино» от Россельхозбанка. Помните, не так давно мы говорили с вами о том, что общего у вина и ИТ? На платформе «Своё вино» мы с редакцией обычно говорим о терруарах, стилях и винтажах, но в этот раз попробуем применить ту же оптику к языкам программирования. Попробуем угадать язык по пяти строкам кода и заодно понять, по каким «ароматам» и «танинам» наш мозг так быстро их различает.

Строю приложение для подсчёта калорий по фото. Пользователь снимает тарелку, модель определяет блюдо, считает КБЖУ. Идея не новая, но мне важно, чтобы это работало именно на русской еде — борщи, гречки, котлеты по-домашнему.
В какой-то момент стало некомфортно: я не знал, насколько модель вообще точна. «Кажется, работает нормально» — плохой ответ, если хочешь что-то улучшать. Решил померять нормально.
Расскажу, что и как мерил, что получил — и про неожиданный вывод в конце, ради которого, честно говоря, и стоило это всё делать.
Спойлер: распознавание оказалось готовым к проду (93.9%), а вот confidence от модели — почти константой, на которой нельзя строить логику. И главная ошибка в калориях пряталась совсем не там, где я её искал.

Агенты сейчас пишут тесты уже за многими из нас, будем объективны, все больше людей кидаем таску ему - получают пачку аппрувов и погнали все это мержить
Но есть, скажем так, ненулевой шанс, что сгенерированные тесты окажутся произведением искусства мусором, который ничего не проверяет (и нет, не шутка, мне коллеги буквально показывали тесты где просто вызывается функция и проверяется что ошибка nil и на этом все, а результат просто всегда игнорировался)
И в таких кейсах очень классная картина: у вас зеленный CI, прод сломан, и вопрос:

Если вы пишете на Go и работаете с SQL-базами, вы знаете эту боль. Каждый CRUD-запрос — ручной SQL-строка, rows.Scan для каждого поля, Begin/Commit/Rollback вокруг записи, и постоянная синхронизация DDL-схемы с кодом. Шаблонный код не заканчивается никогда.
Это рассказ о sqlh — библиотеке, которая убирает всё это, оставаясь в «золотой середине» между raw SQL (слишком много работы) и тяжёлыми ORM (слишком много магии).

В этой статье я расскажу, на какие подводные камни я споткнулся при разработке своего пет‑проекта — мониторинга сайтов на Golang, аналог UptimeRobot.
Начнем издалека... Я хотел разработать пет‑проект, но не банальный todolist, а что‑то свежее, интересное в плане архитектуры и реализации. Шерстя по просторам интернета, я наткнулся на UptimeRobot — сервис для мониторинга сайтов. Азарт и любопытство взяли верх и я начал продумывать, как буду разрабатывать «свой» UptimeRobot. Думал — делов на пару недель от силы. Ведь принцип прост: дергать URL по таймеру и проверять код ответа и всё. Но на практике все оказалось намного сложнее, чем я изначально представлял...

Привет, Хабр! В прошлых статьях я описала, как через нововведенный параметр TSI теоретически можно определить грейд разработчика.

Рассмотрим пример сборки go приложения для работы в среде Entware на mips-роутерах Keenetic/Netcraze

Недавно знакомый попросил помочь с небольшой задачей по проверке внешнего периметра сети компании. Сразу уточню: речь шла об инфраструктуре, на проверку которой было разрешение.
Под внешним периметром обычно понимают всё, что доступно из интернета: публичные IP-адреса, домены, поддомены, облачные или VPS-серверы, а также сервисы, которые слушают внешние порты.
Задача была простой по формулировке, но интересной технически: нужно понять, какие адреса доступны извне и к каким портам можно подключиться.

Наверное, через это уже прошёл каждый из нас :)
Где-то после полугода очень достаточно работы с агентами я стал принимать диффы быстрее, чем успеваю реально в них вникнуть, в итоге в один из я оказался в ситуации, что словил баг, а на поиски проблемы потратил чуть больше часа, а найдя ее, я понял, на сколько она была тривиальной
Короче говоря, то что мы используем агентов - конечно суперсила, но в итоге, мы все начинаем идти по “Accepted driven development” , а это уже начинает сильно отупливать влиять на наши с вами когнитивные возможности :) ну и на наши умения в разработке в целом
Спойлер: это все решается, но нет, не тем что мы перестаем читать в целом код
Меня зовут Эдгар Сипки, я founder easyp & sipki tech и отбираю доклады на Golang Conf в программном комитете. А в своём тг-канале делюсь прикладными AI-инструментами и подходами для разработки - подписывайтесь, дальше будет больше :)
Так вот, обратно к теме. В этой статье я дам промпт-генератор, который соберёт learning skills под ваш проект - чтобы агенты и дальше ускоряли вас, а понимание собственного кода оставалось вашим, а не делегировалось модели :) Но сначала про сама проблему: снаружи-то это кажется все на увеличение нашего KPI, вроде ты и быстрее двигаешься, меньше застреваешь, да и в целом не тратишь часы на написания кода, но вот позже уже начинаются проблемы
Когда надо объяснить, что именно ты только что принял. Какие инварианты поменялись? Почему решение такое? Какие edge cases теперь важны? Что сломается через месяц, если кто-то тронет соседний кусок кода? (а это будет не редко)