Golang Дайджест
8.18K subscribers
39 photos
1 file
187 links
Самое интересное из мира Go: новости, статьи, проекты, сервисы, изменения в языке и др.

Посты публикуются не часто - только самое важное, с чем я лично ознакомился.

Поэтому можно не мьютить канал =)

Обратная связь: @justskiv
Download Telegram
Bubble Tea — TUI-фреймворк для Go

https://habr.com/ru/articles/939574/

Коротенький обзор фреймворка Bubble Tea. Сам обзор ни чем особо не примечателен, но фреймворк шикарный, очень рекомендую. Если вы любите красивые консольные утилиты. вам точно понравится.

#article #tui
👍11🔥8
Golang Дайджест
Bubble Tea — TUI-фреймворк для Go https://habr.com/ru/articles/939574/ Коротенький обзор фреймворка Bubble Tea. Сам обзор ни чем особо не примечателен, но фреймворк шикарный, очень рекомендую. Если вы любите красивые консольные утилиты. вам точно понравится.…
🦄 Экосистема Charm: полезные инструменты для терминала

Раз уж на то пошло, советую обратить внимание вообще на все проекты Charm, там много интересного. Например:

- Bubbles — готовые компоненты для Bubble Tea: текстовые поля, списки, таблицы, прогресс-бары, спиннеры.

- Lip Gloss — библиотека стилей для терминальных приложений. Цвета, рамки, отступы, выравнивание — всё как в CSS, только для консоли. Используется как база для Bubble Tea.

- Gum — эдакий мост между Bubbles / Lip Gloss и shell-скриптами. То есть, можно делать те же красивые скрипты, но без кода на Go.

- Glow — рендеринг Markdown прямо в терминале с подсветкой синтаксиса и красивым форматированием. Можно читать README не выходя из консоли.

- VHS — записывает GIF/видео демонстраций терминальных приложений через простой скрипт. Идеально для документации и README.

- Soft Serve — self-hosted Git-сервер с TUI интерфейсом. Можно красиво смотреть репозитории, коммиты и файлы прямо через SSH

Ну и наше любимое:
- Crushкрасивый консольный ИИ-агент . Поддерживает разные LLM (Claude, GPT, Gemini), использует LSP для контекста как в IDE, можно переключаться между моделями на лету.

Это только самое интересное, но там ещё много всякого. Советую пройтись по всему списку проектов и ознакомиться с каждым.

Вся экосистема построена вокруг идеи: терминал может быть красивым и удобным. И у них это отлично получается

Ну да, люблю я свистелки и перделки, теперь вы знаете обо мне всё 💅

Теперь подумываю сделать большое обзорное видео про всё это. Будет ли вам такое интересно?

#cli #tui
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍18🔥41
🐳 Container-aware GOMAXPROCS: Go наконец-то видит лимиты контейнеров

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

Go Team решили давнюю проблему совместимости с контейнерами. До версии 1.25 Go определял все ядра хоста, не учитывая CPU limits контейнера. Теперь GOMAXPROCS выставляется в соответствии с лимитами автоматически.

Суть проблемы:

- Контейнеру выделено 2 CPU на машине с 128 ядрами
- Go видит 128 ядер, создаёт кучу тредов
- Linux throttling тормозит приложение каждые 100ms
- Tail latency растёт

Что изменилось в 1.25:

- Go читает cgroup CPU limits и ставит GOMAXPROCS по ним
- Динамически обновляется при изменении лимитов
- Работает из коробки — просто обновите go.mod
- CPU requests игнорируются (только limits)

————

Наконец-то.. Проблеме много лет, и всё это время приходилось костылить через uber/automaxprocs или ENV-переменные. А теперь оно работает из коробки, как и должно было уже давно.

P.S. В Java эту проблему решили ещё в 2017 году 😩

#go1_25 #go_official #kubernetes #docker
Please open Telegram to view this post
VIEW IN TELEGRAM
20🔥18🤯2🤔1
Николай Тузов
🥂Выпуск про Go 1.25 уже доступен / GoGetPodcast 17 https://youtu.be/fHuJNsZPCJ0 Этого ролика вам точно будет достаточно для полного понимания нововведений, вне зависимости от вашего опыта Подробно обсудили, что нового в новой версии, зачем это нужно, как…
🥂Что нового в Go 1.25 — глубокий разбор изменений / GoGetPodcast

https://youtu.be/fHuJNsZPCJ0

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

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

Дима был очень хорош, такого подробного и глубокого разбора вы больше нигде не увидите, а с комментариями Глеба оно ещё круче, очень рекомендую.

#gogetpodcast #podcast
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍63
Forwarded from Go Update
🏗️ gogrep — инструмент для семантического поиска внутри вашей кодовой базы. 🏗️

Наверняка много кому приходилось сталкиваться с ситуацией «надо по коду найти вызовы по определенному паттерну». Чаще всего для этого мы используем регулярные выражения (grep, ag, rg). Однако у них всех есть один минус — они интерпретируют файлы как текст, а не как код. Из-за этого в результаты поиска попадают как нужные нам места вызова, так и комментарии, участки текста и прочая.

Решение этой проблемы: семантический поиск. Это когда утилита разбивает файл на синтаксическое дерево и производит поиск уже по самому дереву. Приведу простой пример:

~/mws/api > gogrep . 'ptr.Get($_)'


Здесь мы явно говорим: найди все вызовы, у которых слева есть идентификатор ptr а внутри вызова идет только один аргумент (не важно выражение, их сумма, или переменная). Таким образом мы идентифицируем именно конкретные места которые будут частью компилируемого кода.

Документация по gogrep доступна тут. С описанием синтаксиса немного сложнее: большую (и лучшую) часть информации по мэтчингу и по фильтрам можно найти в тестах. Сама тулза является часть куда более мощной тулзы go-ruleguard (которая кстати входит в golangci-lint).

За обе утилиты огромнейшее спасибо Искандеру Шарипову.
🔥11👍1
Go Update
🚀 Расширение функции new для создания указателя на значения 🚀 Отличные новости! Предложение, обсуждение которого которого длится уже больше четырех лет и которое выдвинул сам Роб Пайк, наконец-то подходит к принятию. В чем суть: есть у нас встроенная функция…
Наконец-то можно будет выкинуть из проектов мой "любимый" lo.ToPtr()

Правда остаётся ещё lo.FromPtr(), но надежда уже есть.

Если что, мне жутко не нравится идея тащить в проект samber/lo, но не всегда удаётся с этим бороться. При этом, я даже не знаю что хуже — тащить этого монстра ради пары строк кода, или же желание использовать ещё больше его функционала 😩

К слову, в предыдущем выпуске подкаста тема `lo` очень подробно обсуждалась
в самом конце. Советую послушать, если нужны аргументы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥32
Forwarded from Go Update
✔️ errors.AsType — типобезопастная замена errors.As ✔️

Тем временем, в 1.26 нас (вероятно) ждет еще одно приятное изменение: дженерики наконец доберутся до пакета errors.

Все изменение проще описать тремя строчками кода. В 1.25 у нас вот так:


var pe *fs.PathError
if errors.As(err, &pe) {
fmt.Println("Failed at path:", pe.Path)
}


А в 1.26 можно будет вот так:


if pe, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println("Failed at path:", pe.Path)
}


Вроде и небольшое изменение, но оно ведет, как минимум, к двум положительным вещам:
• Зона видимости типизированной ошибки во многих участках у нас теперь будет меньше, а значит меньше захламляется пространство имен и снижается необходимость думать над правильным именем для ошибки.
• В отличии от errors.As, который вторым аргументом принимал any, новая функция принимает только тех, кто реализует интерфейс error. Несмотря на то, что у нас есть проверка внутри go vet проверяющая второй аргумент у As, всегда приятнее когда компилятор может самостоятельно поймать ошибку на этапе сборки приложения.

Кстати, причина по которой сигнатура текущей функции выглядит как As(err error, target any) bool заключается в том, что указатель на интерфейс и указатель на тип реализующий интерфейс для компилятора две несовместимые конструкции. Иначе говоря, вот такой код


func As(err error, target *error) bool {
panic("unimplemented")
}



pe *fs.PathError
if As(err, &pathError) {
fmt.Println("Failed at path:", pathError.Path)
}





компиляцию не пройдет. А причина в том, что интерфейсы у нас это отдельная сущность которая существует не только во время компиляции, но и во время выполнения.
🔥283
Forwarded from go-with-me
⚡️ Concurrency Patterns. Fan In
В предыдущем посте мы немного напутали с определением такого многопоточного паттерна как Fan Out

На деле мы показывали Tee, который распространяет одно и то же значение V из канала-источника на N каналов-потребителей

Отличие Fan Out от Tee в том, что на N каналов распространяются разные значения из одного канала-источника. Тобишь, воркеры тянут значения из одного канала, борясь за них насмерть

Лирическое отступление закончено, наша совесть чиста, а сегодняшняя тема будет посвящена Fan In

Этот паттерн является обратным для Fan-Out. Мы собираем данные из нескольких каналов-источников и направляем их в один общий канал-потребитель


1. Default
Итак, что мы имеем?
— Есть воркеры — они кладут значения в N каналов и являются продьюсерами
— Каждый из этих N каналов будет получать значения от своего продьюсера. Назовем такие каналы "стоковыми"
— Есть один общий канал out, туда будет нужно отправить все значения из стоковых каналов
— Для этого мы запускаем N потоков, каждый из которых слушает свой стоковый канал, куда кладет значения продьюсер и редиректит все значения в out

Playground пример

Но что же будет, если какой-то наш продьюсер потух и больше не шлет никаких значений, а передаггый контекст не отменен? Как бы нам понять, что воркер не является активным и перезапустить его? — в этом нам поможет такой механизм как "Heartbeats"

Heartbeat — это регулярное сообщение от продьюсера/воркера, подтверждающее, что он жив и работает


2. Heartbeats
Приступим к рассмотрению этого чуда!

Основная идея проста:
— Имеем структуру, которая хранит в себе стоковый канал, используемый как пайп между воркером и стоком, и канал "сердцебиений"
— Функция Supervise ответственна за отслеживание "сердцебиений" и перезапуск воркера при их отсутствии по TTL
— Функция FanIn принимает на вход стоковые каналы и возвращает результирующий канал, из которого можно читать данные

Всмотримся в наши функции поподробнее

2.1. FanIn
— Не отклоняемся от цели: выкачиваем данные из стоковых каналов и перекладываем в out, реагируя на контекст и неблокирующе отправляя "сердцебиение" нашему супервизору, который пристально наблюдает за нашими воркерами
WaitGroup здесь так же используется для того, чтобы дождаться конца работы наших стоков и отдать управление основному потоку
после дренажа всех "живых" значений

2.2 Supervise
— Создаем стоковый канал и канал "сердцебиений", агрегируем эти значения в структуре Source и возвращаем ее
— В отдельном потоке запускаем нашу рутину по отслеживанию и перезапуску воркеров

2.2.1 Смотрим на внутренности запущенного потока внутри Supervise
— Изначально происходит создание дочернего контекста с отменой для нашего воркера. Этот контекст будет рулить в тот момент, когда наш TTL пройдет и надо будет потушить воркера
— Создаем ticker, который будет слать ивенты, семантически значащие следующее: "в нашего воркера стреляли и он упал в лужу на..."
После получения ивента мы отменяем контекст и воркер окончательно "задыхается в луже"
— Первично запускаем работягу в отдельном потоке
— Если ловим ивент от тикера: производим отмену контекста, переназначаем этот же контекст и функцию отмены, сбрасываем таймер, и запускаем нового воркера в отдельном потоке
— В случае, когда из стокового потока нам пришло "сердцебиение" мы просто сбрасываем таймер и движемся дальше!

Стоит отметить, что воркеры должны "реагировать" на переданный контекст. Без этого мы получим утечку потоков и черт его знает, чем нам это грозит (профилированием и
устранением проблемы, которой можно было бы и избежать)

Таким образом, мы получаем более надежный Fan In, где все источники данных контролируемы и восстанавливаемы при зависаниях

Playground пример


Статью писали с Дашей: @dariasroom

Stay tuned 😏
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍106🔥3🤯1
conc — удобные примитивы для конкурентного кода

https://github.com/sourcegraph/conc

⭐️ ~10.1k

Небольшая библиотека от Sourcegraph, которая предлагает более безопасные и удобные обёртки над стандартными инструментами конкурентности в Go.

Впервые встретил её на своей текущей работе, и в целом мне понравилось, поэтому грех не поделиться.

Что в ней есть интересного:

- conc.WaitGroup — альтернатива стандартному sync.WaitGroup: ловит паники в горутинах и возвращает их в Wait(), а также не даёт забыть вызвать Wait()

- pool — конкурентный пул задач с ограничением числа горутин (WithMaxGoroutines), сбором ошибок (WithErrors, WithFirstError) и отменой задач при ошибках (WithContext)

- stream — параллельное выполнение задач с сохранением порядка результатов (удобно, когда порядок важен, но хочется параллелизма)

- iter.Map / ForEach — упрощённые хелперы для конкурентной обработки слайсов

🟠 Библиотека пока pre-1.0 (последний релиз в феврале 2023), API может меняться.

#library #concurrency #goroutines
Please open Telegram to view this post
VIEW IN TELEGRAM
14👍11🤯1
Как я пишу HTTP сервисы на Go спустя 13 лет

How I write HTTP services in Go after 13 years

Мэт Райер (Grafana, Go Time podcast) делится опытом, как он пишет HTTP-сервисы после 13 лет работы с Go.

Ключевая мысль статьи: не нужен ни фреймворк, ни DI-магия, всё решается стандартной библиотекой и явными зависимостями.

TL;DR:

- NewServer(...) принимает все зависимости конструктором и возвращает http.Handler. Да, список аргументов может быть длинным, и это нормально — зато всё явно.

- Все роуты в одном месте (routes.go), никакой путаницы.

- main() тонкий, реальная логика в run(ctx, ...) — удобно и для тестов, и для graceful shutdown.

- Тесты поднимают сервис целиком (с /readyz и прочим), а окружение передаётся как параметры функции, без обращения к глобальному состоянию (os.Getenv, flag, os.Stdin/Stdout)

- Хэндлеры собираются фабриками, middleware пишутся обычными функциями func(h http.Handler) http.Handler — всё просто и прозрачно.

————

🟢Что я могу сказать.. Такое ощущение, будто статью писал я сам. Хочу, чтобы каждый мой коллега прочитал её дважды! Я устал регулярно объяснять и защищать все те простые вещи, о которых пишет автор.

Мне даже 13 лет на это не понадобилось, просто учителя были хорошие 👴

Единственное, что вызывает вопросы — это «nil-зависимости» в тестах (автор иногда передаёт nil, если зависимость не используется). Я бы всё же предпочёл простые no-op фейки, чтобы не ловить паники внезапно, пусть даже в тестах — поверьте, фиксить тесты без должной гигиены та ещё морока. Пусть сегодня в конкретном кейсе дело не доходит до какой-то зависимости, но завтра дойдёт.

В остальном подход отличный: код простой и читаемый, тесты пишутся легко, нет магии. Отличная статья, особенно для тех, кто только ещё не набил руку в архитектуре сервисов на Go ❤️

Для новичков must read, опытным товарищам тоже лишним не будет ознакомиться.

#article #http #architecture #english
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥397🤔7👍3
🥂Первая конференция для лидов и менеджеров от Авито Тех

Когда: 17 октября в Москве и онлайн.

Ребята подготовили доклады про лучшие практики управления командами и процессами от экспертов Авито.

Также там будут интерактивные зоны, где можно погрузиться в их менеджерскую культуру, воркшопы и ещё много возможностей для нетворка с лидами больших IT-компаний.

О чём будут говорить:

- Лидерство и развитие до C-level
- AI: как он трансформировал роль тех.руководителей и изменил управление командами
- Адаптивность и процессs в меняющемся мире
- О людях и эффективных отношениях с командами

Полная программа докладов уже на сайте!

Участие бесплатное, но регистрация обязательная. Количество мест ограничено ➡️ avito.tech/conference

#промо #текст_прислан
Please open Telegram to view this post
VIEW IN TELEGRAM
3🤔3👍2🔥1
🔍 Утечка горутин в продакшене — разбор реального кейса

- Оригинальный пост
- Обсуждение на Hacker News

Автор рассказывает про классическую production-проблему: out of memory в k8s-подах посреди во время работы сервиса.
Спойлер: виноваты горутины, которые живут вечно.

Как искали проблему:

- Grafana показала растущее потребление памяти горутинами
- Подключили pprof и какое-то время мониторили результаты
- Нашли фабрику бесконечных горутин 🙃

Виновник — функция конвертации канала:

func ToDoneInterface(done <-chan struct{}) <-chan interface{} {
interfaceStream := make(chan interface{})
go func() {
defer close(interfaceStream)
select {
case <-done: return
}
}()
return interfaceStream
}


Проблема: select{} ждёт сигнала из done, но если контекст никогда не отменяется — горутина блокируется навсегда. defer close() там есть, но он не поможет, если select никогда не вернётся.

Инструменты для поиска утечек:

- Grafana + Pyroscope — flame-графы памяти
- pprof с diff_base — сравнение снапшотов до/после
- goleak — для автоматического обнаружения в тестах

Главная мысль от автора: не конвертируйте каналы!
Используйте обычные паттерны работы с context.Context и не забывайте вызывать .Done() там, где нужно.

————

Что ж, вот вам ещё одно напоминание о том, что Go хоть и простой язык, но конкурентность в нём кусается как везде. И go func() — это не fire-and-forget, как кажется новичкам, а обязательство следить за временем жизни горутины. Опытный разработчик 10 раз подумает перед тем как использовать эту конструкцию где бы то ни было.

#article #concurrency #english
Please open Telegram to view this post
VIEW IN TELEGRAM
👍206🔥3