В этой подробной статье автор показывает, как «обмануть» сборщик мусора Go и создать свой собственный arena-аллокатор на чистом Go, получая существенный прирост производительности.
📌 Что внутри:
- Краткий обзор GC Go: как используются pointer bits и shapes для точного сбора мусора.
- Реализация простого bump-аллокатора Arena, сводящего Alloc к смещению указателя.
- Бенчмарки: до 2×–4× ускорения при малых аллокациях и почти 7× для массивов из 64 элементов ( arena – 7370 MB/s vs new – 2865 MB/s )
mcyoung.xyz
.
- Оптимизация через sync.Pool и финализаторы для повторного использования и ускоренного обнуления памяти.
- Безопасный метод Reset() для мгновенной очистки арены без дорогостоящего выделения заново.
Заготовка примитивного Realloc(), позволяющая расширять последние аллокации «на месте».
Полный код, подробное объяснение и советы по дальнейшим оптимизациям — по ссылке:
https://mcyoung.xyz/2025/04/21/go-arenas/
@golang_books
Please open Telegram to view this post
VIEW IN TELEGRAM
Любое приложение должно при завершении работы:
1. Закрыть точку входа (HTTP-сервер, очередь сообщений и т.д.), но сохранить исходящие соединения (БД, кэш) активными.
2. Дождаться окончания всех текущих запросов, и при превышении допустимого времени вернуть корректную ошибку.
3. Освободить критические ресурсы (соединения с БД, файловые блокировки, слушатели). :contentReference[oaicite:0]{index=0}
## 1. Обработка сигналов
В Unix-системах сигналы (`SIGTERM`, SIGINT, SIGHUP`) — это программные прерывания, уведомляющие процесс о необходимости завершения или перезагрузки конфигурации. По умолчанию Go-рантайм ловит многие сигналы, но для «мягкой» остановки обычно интересуют только `SIGTERM и SIGINT. :contentReference[oaicite:1]{index=1}
func main() {
// 1) Создаем канал для сигналов
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
// 2) Запускаем сервер и другую работу здесь...
// 3) Ждем сигнала
<-signalChan
fmt.Println("Received termination signal, shutting down…")
}
2. Таймаут для завершения
В Kubernetes по умолчанию даётся 30 секунд на грациозную остановку (terminationGracePeriodSeconds). Хорошей практикой является резервирование 20 % времени (примерно 6 секунд) на «подстраховку» завершения.
timeout := 25 * time.Second
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatalf("Server forced to shutdown: %v", err)
}
3. Остановка приёма новых запросов
Метод http.Server.Shutdown закрывает слушатели и не принимает новые соединения, при этом дожидаясь окончания активных хэндлеров. Однако в контейнеризированных окружениях нужно сначала «провалить» readiness-пробу, чтобы снять под из балансировщика, и только затем вызывать Shutdown.
VictoriaMetrics
var shuttingDown atomic.Bool
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
if shuttingDown.Load() {
w.WriteHeader(http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
})
// При получении сигнала:
shuttingDown.Store(true)
// Ждем несколько секунд, пока traffic прекратится
time.Sleep(5 * time.Second)
server.Shutdown(ctx)
4. Обработка активных запросов
После вызова Shutdown(ctx) сервер ждет либо завершения всех соединений, либо истечения контекста. Чтобы уведомить свои хэндлеры о «скоро закрытии», используйте контекст:
a) Middleware с каналом отмены
func WithGracefulShutdown(next http.Handler, cancelCh <-chan struct{}) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := WithCancellation(r.Context(), cancelCh)
defer cancel()
next.ServeHTTP(w, r.WithContext(ctx))
})
}
b) BaseContext для всего сервера
ongoingCtx, cancelFn := context.WithCancel(context.Background())
server := &http.Server{
Addr: ":8080",
Handler: yourHandler,
BaseContext: func(_ net.Listener) context.Context { return ongoingCtx },
}
// После готовности к остановке:
cancelFn()
VictoriaMetrics
5. Освобождение ресурсов
Не закрывайте ресурсы сразу при получении сигнала — хэндлеры могут ими ещё пользоваться. Лучше дождаться окончания работы (или таймаута), а затем в обратном порядке инициализации вызвать Close. Стандартный приём в Go — defer:
db := connectDB()
defer db.Close()
cache := connectCache()
defer cache.Close()
ОС сама освободит память и файловые дескрипторы при завершении процесса, но для внешних систем (БД, брокеры сообщений) рекомендуются явные Close()/Flush() для корректного завершения транзакций и избежания потерь данных.
VictoriaMetrics
- Ловим нужные сигналы и переключаемся на собственную логику.
- Останавливаем приём новых запросов через Shutdown и/или провал readiness-пробы.
- Ждём завершения активных запросов в пределах таймаута и закрываем ресурсы в обратном порядке.
@golang_books
Please open Telegram to view this post
VIEW IN TELEGRAM
🛠 Создание собственного ResponseWriter: безопасный HTTP в Go
*Автор: Антонио Питаси*
*Источник: [anto.pt](https://anto.pt/articles/go-http-responsewriter)*
📌 Основная идея
В Go интерфейс
• Забывание установки кода состояния ответа.
• Попытка изменить заголовки после начала записи (это не вызовет ошибок, но и не сработает).
• Продолжение выполнения обработчика даже после ошибок, что может повлиять на корректность ответа.
➡ Решение: создать собственную обёртку для
⚠️ Проблемы стандартного ResponseWriter
1️⃣ Автоматическая установка кода состояния:
Go сам устанавливает код 200 OK при первом вызове
2️⃣ Изменение заголовков после начала записи:
После начала отправки тела ответа заголовки нельзя изменить. Go не сигнализирует об этом явно.
3️⃣ Выполнение после ошибок:
Обработчик продолжает выполнение даже после отправки ошибки, если вы забыли поставить
## 🧱 Пример реализации обёртки
## 🔄 Интеграция через middleware
Чтобы все обработчики автоматически использовали новый
✅ Преимущества
• Явное требование установки кода состояния.
• Логирование попыток записи без
• Блокировка записи при статусах >=500 для предотвращения некорректного ответа.
• Улучшенная предсказуемость и безопасность обработки HTTP-запросов.
🔗 Подробнее в оригинальной статье
*Автор: Антонио Питаси*
*Источник: [anto.pt](https://anto.pt/articles/go-http-responsewriter)*
📌 Основная идея
В Go интерфейс
http.ResponseWriter
напрямую записывает данные в сокет, что может приводить к незаметным ошибкам:• Забывание установки кода состояния ответа.
• Попытка изменить заголовки после начала записи (это не вызовет ошибок, но и не сработает).
• Продолжение выполнения обработчика даже после ошибок, что может повлиять на корректность ответа.
➡ Решение: создать собственную обёртку для
ResponseWriter
, чтобы добавить проверки и сделать обработку HTTP-запросов более безопасной и предсказуемой.⚠️ Проблемы стандартного ResponseWriter
1️⃣ Автоматическая установка кода состояния:
Go сам устанавливает код 200 OK при первом вызове
Write()
, если вы забыли явно вызвать WriteHeader()
. Это скрывает ошибки.2️⃣ Изменение заголовков после начала записи:
После начала отправки тела ответа заголовки нельзя изменить. Go не сигнализирует об этом явно.
3️⃣ Выполнение после ошибок:
Обработчик продолжает выполнение даже после отправки ошибки, если вы забыли поставить
return
.## 🧱 Пример реализации обёртки
type HttpWriter struct {
w http.ResponseWriter
headerWritten bool
statusCode int
}
func NewHttpWriter(w http.ResponseWriter) http.ResponseWriter {
return &HttpWriter{w: w}
}
func (w *HttpWriter) Header() http.Header {
return w.w.Header()
}
func (w *HttpWriter) WriteHeader(statusCode int) {
w.w.WriteHeader(statusCode)
w.headerWritten = true
w.statusCode = statusCode
}
func (w *HttpWriter) Write(data []byte) (int, error) {
if !w.headerWritten {
log.Println("⚠️ Предупреждение: Write() вызван без предварительного WriteHeader()")
}
if w.statusCode >= 500 {
log.Println("⚠️ Статус 500: запись игнорируется")
return 0, nil
}
return w.w.Write(data)
}
## 🔄 Интеграция через middleware
Чтобы все обработчики автоматически использовали новый
HttpWriter
, можно внедрить его через middleware:
func middleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
writer := NewHttpWriter(w)
h.ServeHTTP(writer, r)
})
}
✅ Преимущества
• Явное требование установки кода состояния.
• Логирование попыток записи без
WriteHeader()
. • Блокировка записи при статусах >=500 для предотвращения некорректного ответа.
• Улучшенная предсказуемость и безопасность обработки HTTP-запросов.
🔗 Подробнее в оригинальной статье
🛠 Массовая конвертация изображений с использованием Go и параллелизма
🔍 Проблема
• При запуске маркетплейса векторных изображений [Vectopus.com](https://vectopus.com) разработчики забыли реализовать поддержку формата WebP
• Это ухудшало SEO и замедляло загрузку страниц
• Нужно было конвертировать 500 000+ SVG-файлов в WebP _ретроспективно_
⚙️ Решение: CLI-инструмент на Go
Создан инструмент на Go, обрабатывающий SVG-файлы в несколько этапов:
1. Загрузка SVG из Amazon S3
2. Конвертация в PNG
3. Добавление водяного знака (опционально)
4. Конвертация PNG в WebP
5. Загрузка WebP обратно в S3
6. Обновление метаданных в PostgreSQL
7. Удаление временных файлов
⏱ Задача, рассчитанная на несколько дней, была выполнена за несколько часов.
🗃 Архитектура хранилища
• Все изображения — в Amazon S3 (SVG — приватный бакет, PNG — публичный)
• Метаданные — в PostgreSQL с полиморфными связями
• Новые загрузки обрабатываются через SQS + Lambda + EventBridge
✅ Выводы
• Использование Go дало высокую производительность при низких издержках
• Масштабируемость и надёжность решения
• Параллелизм Go отлично подходит для batch-обработки медиа
📖 Подробнее
🔍 Проблема
• При запуске маркетплейса векторных изображений [Vectopus.com](https://vectopus.com) разработчики забыли реализовать поддержку формата WebP
• Это ухудшало SEO и замедляло загрузку страниц
• Нужно было конвертировать 500 000+ SVG-файлов в WebP _ретроспективно_
⚙️ Решение: CLI-инструмент на Go
Создан инструмент на Go, обрабатывающий SVG-файлы в несколько этапов:
1. Загрузка SVG из Amazon S3
2. Конвертация в PNG
3. Добавление водяного знака (опционально)
4. Конвертация PNG в WebP
5. Загрузка WebP обратно в S3
6. Обновление метаданных в PostgreSQL
7. Удаление временных файлов
⏱ Задача, рассчитанная на несколько дней, была выполнена за несколько часов.
🗃 Архитектура хранилища
• Все изображения — в Amazon S3 (SVG — приватный бакет, PNG — публичный)
• Метаданные — в PostgreSQL с полиморфными связями
• Новые загрузки обрабатываются через SQS + Lambda + EventBridge
✅ Выводы
• Использование Go дало высокую производительность при низких издержках
• Масштабируемость и надёжность решения
• Параллелизм Go отлично подходит для batch-обработки медиа
📖 Подробнее
📚 Организация middleware в Go без сторонних зависимостей
Если ты пишешь веб-приложения на Go и хочешь избавиться от внешних зависимостей вроде
https://www.alexedwards.net/blog/organize-your-go-middleware-without-dependencies
📌 В чем суть:
• Проблема: стандартная библиотека Go не даёт удобного способа цепочечного подключения middleware
• Цель: избежать дублирования кода и сделать middleware масштабируемыми без сторонних пакетов
💡 Решение — создать собственный тип
Теперь ты можешь описывать цепочки middleware так:
Этот подход:
• Простой
• Без зависимостей
• Легко расширяется
Полная статья и объяснения тут:
@golang_books
Если ты пишешь веб-приложения на Go и хочешь избавиться от внешних зависимостей вроде
alice
, статья от Алекса Эдвардса — must read: https://www.alexedwards.net/blog/organize-your-go-middleware-without-dependencies
• Проблема: стандартная библиотека Go не даёт удобного способа цепочечного подключения middleware
• Цель: избежать дублирования кода и сделать middleware масштабируемыми без сторонних пакетов
💡 Решение — создать собственный тип
chain
, который позволяет «наматывать» middleware на обработчики:
type chain []func(http.Handler) http.Handler
func (c chain) then(h http.Handler) http.Handler {
for i := len(c) - 1; i >= 0; i-- {
h = c[i](h)
}
return h
}
func (c chain) thenFunc(h http.HandlerFunc) http.Handler {
return c.then(h)
}
Теперь ты можешь описывать цепочки middleware так:
mux := http.NewServeMux()
baseChain := chain{requestID, logRequest}
adminChain := append(baseChain, authenticateUser, requireAdminUser)
mux.Handle("GET /", baseChain.thenFunc(home))
mux.Handle("GET /admin", adminChain.thenFunc(showAdminDashboard))
Этот подход:
• Простой
• Без зависимостей
• Легко расширяется
Полная статья и объяснения тут:
@golang_books
Please open Telegram to view this post
VIEW IN TELEGRAM
🔧 Terraform + Argo CD: современный способ интеграции для GitOps
В этой свежей статье предложен элегантный способ связать Terraform и Argo CD в рамках GitOps-подхода.
📌 В чём проблема:
Terraform управляет инфраструктурой, а Argo CD — приложениями в Kubernetes. Но часто возникает разрыв: как передавать выходные данные Terraform (outputs) в Argo CD, чтобы оно подхватывало созданные ресурсы (например, адреса сервисов, пути, переменные)?
🧠 Ключевая идея:
Использовать multi-source Argo CD Application — это позволяет в одном объекте
- один для output’ов из Terraform (в виде YAML-файлов)
- второй — с настоящими Kubernetes-манифестами приложений
🛠 Пример потока:
1. Terraform генерирует output-файл (например, с URL или secrets) и коммитит в Git
2. Argo CD отслеживает этот файл как отдельный источник
3. Приложение автоматически получает эти значения и применяет манифесты с учётом output’ов
🎯 Зачем это нужно:
• меньше ручной синхронизации
• больше автоматизации в CI/CD
• централизованный контроль через Git
• минимальные костыли: без сторонних скриптов, прокладок и Helm magic
📎 Поддерживается в Argo CD начиная с версии 2.6+
Подробный YAML-пример и реализация — в оригинальной статье 👉 [akuity.io](https://akuity.io/blog/yet-another-take-on-integrating-terraform-with-argo-cd)
💡 Отличный способ повысить чистоту GitOps и устранить разрыв между инфраструктурой и приложениями.
📌 Читать
В этой свежей статье предложен элегантный способ связать Terraform и Argo CD в рамках GitOps-подхода.
📌 В чём проблема:
Terraform управляет инфраструктурой, а Argo CD — приложениями в Kubernetes. Но часто возникает разрыв: как передавать выходные данные Terraform (outputs) в Argo CD, чтобы оно подхватывало созданные ресурсы (например, адреса сервисов, пути, переменные)?
🧠 Ключевая идея:
Использовать multi-source Argo CD Application — это позволяет в одном объекте
Application
подключить сразу несколько Git-репозиториев или путей:- один для output’ов из Terraform (в виде YAML-файлов)
- второй — с настоящими Kubernetes-манифестами приложений
🛠 Пример потока:
1. Terraform генерирует output-файл (например, с URL или secrets) и коммитит в Git
2. Argo CD отслеживает этот файл как отдельный источник
3. Приложение автоматически получает эти значения и применяет манифесты с учётом output’ов
🎯 Зачем это нужно:
• меньше ручной синхронизации
• больше автоматизации в CI/CD
• централизованный контроль через Git
• минимальные костыли: без сторонних скриптов, прокладок и Helm magic
📎 Поддерживается в Argo CD начиная с версии 2.6+
Подробный YAML-пример и реализация — в оригинальной статье 👉 [akuity.io](https://akuity.io/blog/yet-another-take-on-integrating-terraform-with-argo-cd)
💡 Отличный способ повысить чистоту GitOps и устранить разрыв между инфраструктурой и приложениями.
📌 Читать
🔍 Как работает Beelzebub Honeypot
Beelzebub — это низкокодовая honeypot-фреймворк, позволяющая быстро развернуть ловушки для киберпреступников. Особенность проекта — интеграция с моделью GPT-4o, что обеспечивает реалистичное поведение системы и привлекает злоумышленников для более глубокого анализа их действий.
💰 Исследование криптоджекинга
В рамках одного из экспериментов Beelzebub была зафиксирована атака, при которой злоумышленник использовал вредоносное ПО для:
- Удаления конкурирующих майнеров с системы жертвы.
- Установки собственного майнера xmrig через скрипт с сервера c3pool.org.
beelzebub-honeypot.com
- Майнинга криптовалюты Monero (XMR) на свой кошелек.
За короткий период злоумышленнику удалось добыть 20 XMR, что эквивалентно примерно $4126.
🛡️ Противодействие угрозам
После обнаружения атаки команда Beelzebub:
- Заблокировала вредоносный кошелек в пуле c3pool.
beelzebub-honeypot.com
- Удалили все связанные с ним майнеры, предотвращая дальнейшее распространение угрозы.
📌 Основные преимущества Beelzebub
Быстрая настройка honeypot-серверов через YAML-конфигурации.
- Интеграция с LLM (GPT-4o) для реалистичного взаимодействия с атакующими.
- Открытый исходный код и активное сообщество разработчиков.
- Поддержка различных протоколов (SSH, HTTP, TCP) и интеграция с Docker и Kubernetes.
Beelzebub Honeypot — мощный инструмент для специалистов по кибербезопасности, позволяющий не только выявлять, но и глубоко анализировать современные угрозы, такие как криптоджекинг, и эффективно им противодействовать.
https://beelzebub-honeypot.com/blog/how-cybercriminals-make-money-with-cryptojacking/
Please open Telegram to view this post
VIEW IN TELEGRAM
🛠️ История создания “storage-agnostic” message queue
Автор — Fahim Faisaal — делится опытом разработки гибкой очереди задач на Go, которая может использовать любые хранилища: in-memory, Redis, SQLite и др. :contentReference[oaicite:0]{index=0}
Контекст:
Занимаясь на Go, автор вдохновился инструментами из Node.js экосистемы (BullMQ, RabbitMQ) и захотел сделать что-то похожее, но с нуля, без зависимостей. Так родилась идея — сначала он создал Gocq (Go Concurrent Queue): простую concurrent-очередь, работающую через каналы :contentReference[oaicite:1]{index=1}.
⚡ Основная проблема
Gocq отлично работал в памяти, но не поддерживал устойчивое хранение задач.
Автор задумался: а можно ли сделать очередь, не зависящую от конкретного хранилища — так, чтобы её можно было подключить к Redis, SQLite или совсем без них?
🧱 Как это реализовано в VarMQ
После рефакторинга Gocq был разделён на два компонента:
1. Worker pool — пул воркеров, обрабатывающих задачи.
2. Queue interface — абстракция над очередью, не зависящая от реализации.
Теперь воркер просто берёт задачи из очереди, не зная, где они живут. :contentReference[oaicite:2]{index=2}
---
### 🧠 Пример использования
- In-memory очередь:
- С SQLite-поддержкой:
- С Redis (для распределённой обработки):
В итоге воркер обрабатывает задачи одинаково — независимо от хранилища. :contentReference[oaicite:3]{index=3}
✅ Почему это круто
- Гибкость: адаптеры позволяют легко менять хранилище без правок воркера.
- Минимальные зависимости: в ядре — zero-deps, весь функционал — через адаптеры.
- Self-hosted и легковесно: можно развернуть локально или в продакшене.
- Написано на Go: использует горутины и каналы, удобен и эффективен.
📣 Отзывы сообщества
На Reddit отметили, что автор добился "queue system that doesn’t care if your storage is Redis, SQLite, or even in-memory" :contentReference[oaicite:4]{index=4}
🔗 Ссылки
- Статья: A Story of Building a Storage‑Agnostic Message Queue на DEV :contentReference[oaicite:5]{index=5}
- GitHub VarMQ (Var-storage-agnostic message queue): репозиторий с кодом адаптеров и примерами использования :contentReference[oaicite:6]{index=6}
Итог: VarMQ — это элегантное решение на Go для создания задач-очереди, универсально по отношению к хранилищу: выбрал нужный адаптер — и система работает.
📌 Читать
Автор — Fahim Faisaal — делится опытом разработки гибкой очереди задач на Go, которая может использовать любые хранилища: in-memory, Redis, SQLite и др. :contentReference[oaicite:0]{index=0}
Контекст:
Занимаясь на Go, автор вдохновился инструментами из Node.js экосистемы (BullMQ, RabbitMQ) и захотел сделать что-то похожее, но с нуля, без зависимостей. Так родилась идея — сначала он создал Gocq (Go Concurrent Queue): простую concurrent-очередь, работающую через каналы :contentReference[oaicite:1]{index=1}.
⚡ Основная проблема
Gocq отлично работал в памяти, но не поддерживал устойчивое хранение задач.
Автор задумался: а можно ли сделать очередь, не зависящую от конкретного хранилища — так, чтобы её можно было подключить к Redis, SQLite или совсем без них?
🧱 Как это реализовано в VarMQ
После рефакторинга Gocq был разделён на два компонента:
1. Worker pool — пул воркеров, обрабатывающих задачи.
2. Queue interface — абстракция над очередью, не зависящая от реализации.
Теперь воркер просто берёт задачи из очереди, не зная, где они живут. :contentReference[oaicite:2]{index=2}
---
### 🧠 Пример использования
- In-memory очередь:
w := varmq.NewVoidWorker(func(data any) {
// обработка задачи
}, 2)
q := w.BindQueue()
- С SQLite-поддержкой:
import "github.com/goptics/sqliteq"
db := sqliteq.New("test.db")
pq, _ := db.NewQueue("orders")
q := w.WithPersistentQueue(pq)
- С Redis (для распределённой обработки):
import "github.com/goptics/redisq"
rdb := redisq.New("redis://localhost:6379")
pq := rdb.NewDistributedQueue("transactions")
q := w.WithDistributedQueue(pq)
В итоге воркер обрабатывает задачи одинаково — независимо от хранилища. :contentReference[oaicite:3]{index=3}
✅ Почему это круто
- Гибкость: адаптеры позволяют легко менять хранилище без правок воркера.
- Минимальные зависимости: в ядре — zero-deps, весь функционал — через адаптеры.
- Self-hosted и легковесно: можно развернуть локально или в продакшене.
- Написано на Go: использует горутины и каналы, удобен и эффективен.
📣 Отзывы сообщества
На Reddit отметили, что автор добился "queue system that doesn’t care if your storage is Redis, SQLite, or even in-memory" :contentReference[oaicite:4]{index=4}
🔗 Ссылки
- Статья: A Story of Building a Storage‑Agnostic Message Queue на DEV :contentReference[oaicite:5]{index=5}
- GitHub VarMQ (Var-storage-agnostic message queue): репозиторий с кодом адаптеров и примерами использования :contentReference[oaicite:6]{index=6}
Итог: VarMQ — это элегантное решение на Go для создания задач-очереди, универсально по отношению к хранилищу: выбрал нужный адаптер — и система работает.
📌 Читать
🧪 Go synctest — решение для нестабильных (flaky) тестов
Flaky-тесты в многопоточном Go-коде — боль. Новый экспериментальный инструмент
📌 Что это такое:
•
• все goroutine исполняются детерминированно
• нет зависимости от планировщика и нагрузки ОС
🔧 Пример:
⏱ Даже с
⚙️ Преимущества:
✅ Устранение race-условий при тестировании
✅ Нет задержек —
✅ Можно тестировать поведение с точностью до микросекунды
✅ Подходит для любых
🚫 Ограничения:
• Пока экспериментально: нужно запускать с
• Не подходит для ввода-вывода, работы с сетью или временем вне "bubble"
📖 Подробнее:
https://victoriametrics.com/blog/go-synctest/
Flaky-тесты в многопоточном Go-коде — боль. Новый экспериментальный инструмент
synctest
из Go 1.24 решает эту проблему с помощью синтетического времени и контроля исполнения goroutine.📌 Что это такое:
synctest
— специальный режим, запускающий тесты в изолированной "песочнице", где:•
time.Sleep
не ждёт реального времени • все goroutine исполняются детерминированно
• нет зависимости от планировщика и нагрузки ОС
🔧 Пример:
import "testing/synctest"
func TestSharedValue(t *testing.T) {
synctest.Run(func() {
var shared atomic.Int64
go func() {
shared.Store(1)
time.Sleep(1 * time.Microsecond)
shared.Store(2)
}()
time.Sleep(5 * time.Microsecond)
if shared.Load() != 2 {
t.Errorf("shared = %d, want 2", shared.Load())
}
})
}
⏱ Даже с
Sleep
, результат всегда стабилен. Без synctest
такой тест может иногда проваливаться.⚙️ Преимущества:
✅ Устранение race-условий при тестировании
✅ Нет задержек —
Sleep
срабатывает мгновенно ✅ Можно тестировать поведение с точностью до микросекунды
✅ Подходит для любых
atomic
, mutex
, select
, time.After
и др.🚫 Ограничения:
• Пока экспериментально: нужно запускать с
GOEXPERIMENT=synctest
• Не подходит для ввода-вывода, работы с сетью или временем вне "bubble"
📖 Подробнее:
https://victoriametrics.com/blog/go-synctest/
Расширенный_гайд_по_Docker_для_DevOps_специалистов_1_2.pdf
391.1 KB
• как устроен Docker изнутри
• как упаковать любое приложение в контейнер
• как запускать десятки сервисов одной командой
• как дебажить, оптимизировать и защищать контейнеры
• как не сойти с ума с volumes, networks и образами
Сохраняй и делись с коллегами, чтобы не потерять
@golang_books
Please open Telegram to view this post
VIEW IN TELEGRAM
📢 GORM теперь поддерживает дженерики — работа с БД в Go стала ещё проще и безопаснее!
С версии GORM v1.30.0 появилась полноценная поддержка дженериков (Go 1.18+), которая позволяет писать более выразительный и типобезопасный код без шаблонных повторов.
🔧 Пример:
✅ Что это даёт:
• Типобезопасность на этапе компиляции
• Более компактный и читаемый код
• Лёгкая интеграция с
• Улучшенный DX (developer experience)
📎 Документация: https://gorm.io/docs/the_generics_way.html
Если ты пишешь на Go и используешь GORM — самое время перейти на новый стиль.
С версии GORM v1.30.0 появилась полноценная поддержка дженериков (Go 1.18+), которая позволяет писать более выразительный и типобезопасный код без шаблонных повторов.
🔧 Пример:
ctx := context.Background()
// Создание
gorm.G[User](db).Create(ctx, &User{Name: "Alice"})
// Поиск
user, err := gorm.G[User](db).Where("name = ?", "Alice").First(ctx)
// Обновление
gorm.G[User](db).Where("id = ?", user.ID).Update(ctx, "age", 30)
// Удаление
gorm.G[User](db).Where("id = ?", user.ID).Delete(ctx)
✅ Что это даёт:
• Типобезопасность на этапе компиляции
• Более компактный и читаемый код
• Лёгкая интеграция с
OnConflict
, Joins
, Hints
, Preload
и пр. • Улучшенный DX (developer experience)
📎 Документация: https://gorm.io/docs/the_generics_way.html
Если ты пишешь на Go и используешь GORM — самое время перейти на новый стиль.
🚀 Кэширование в Go: как делать правильно
В свежей статье от Leapcell рассматриваются ключевые аспекты эффективного кэширования в Go:
- Планирование объёма памяти: важно заранее оценить, сколько данных будет кэшироваться, чтобы избежать переполнения памяти (OOM).
- Классификация данных: разделение данных на "горячие" и "холодные" помогает оптимизировать использование ресурсов, сохраняя часто используемые данные в быстром доступе, а редко используемые — на более экономичных носителях.
- Стратегии кэширования в распределённых системах:
- Использование распределённого кэша (например, Redis).
- Направление одинаковых запросов на один и тот же экземпляр приложения.
- Репликация кэша на каждом экземпляре приложения.
- Политики вытеснения: применение алгоритма LRU (Least Recently Used) помогает контролировать размер кэша, удаляя наименее используемые элементы.
Подробнее: https://dev.to/leapcell/caching-in-go-doing-it-right-25i5
В свежей статье от Leapcell рассматриваются ключевые аспекты эффективного кэширования в Go:
- Планирование объёма памяти: важно заранее оценить, сколько данных будет кэшироваться, чтобы избежать переполнения памяти (OOM).
- Классификация данных: разделение данных на "горячие" и "холодные" помогает оптимизировать использование ресурсов, сохраняя часто используемые данные в быстром доступе, а редко используемые — на более экономичных носителях.
- Стратегии кэширования в распределённых системах:
- Использование распределённого кэша (например, Redis).
- Направление одинаковых запросов на один и тот же экземпляр приложения.
- Репликация кэша на каждом экземпляре приложения.
- Политики вытеснения: применение алгоритма LRU (Least Recently Used) помогает контролировать размер кэша, удаляя наименее используемые элементы.
Подробнее: https://dev.to/leapcell/caching-in-go-doing-it-right-25i5
🚀 Go — идеально подходит для AI-агентов
Агент дорогим в использовании (например, из-за использования LLM), и часто требует взаимодействия с пользователем или другими агентами.
⚙️ Преимущества Go для работы с агентами:
- Go позволяет запускать тысячи горутин с минимальными накладными расходами, что идеально подходит для масштабируемых агентных систем.
- Общение через каналы: Go поощряет передачу данных через каналы, что упрощает синхронизацию и уменьшает вероятность ошибок, связанных с общим доступом к памяти.
- Контекстное управление: Механизм context.Context в Go обеспечивает централизованное управление отменой операций, что особенно полезно для долгоживущих процессов.
- Богатая стандартная библиотека: Go предоставляет обширный набор инструментов для работы с сетью, JSON, криптографией и другими аспектами, необходимыми для разработки агентов.
- Профилирование: Инструменты, такие как pprof, позволяют эффективно отслеживать и устранять утечки памяти и горутин.
🙅 Минусы:
— Мало библиотек для ML
— Нет "магии" как у Python-экосистемы
Но если тебе важны надежность, скорость и контроль, Go — это отличный выбор 🔥
📖 Читать полностью
Агент дорогим в использовании (например, из-за использования LLM), и часто требует взаимодействия с пользователем или другими агентами.
⚙️ Преимущества Go для работы с агентами:
- Go позволяет запускать тысячи горутин с минимальными накладными расходами, что идеально подходит для масштабируемых агентных систем.
- Общение через каналы: Go поощряет передачу данных через каналы, что упрощает синхронизацию и уменьшает вероятность ошибок, связанных с общим доступом к памяти.
- Контекстное управление: Механизм context.Context в Go обеспечивает централизованное управление отменой операций, что особенно полезно для долгоживущих процессов.
- Богатая стандартная библиотека: Go предоставляет обширный набор инструментов для работы с сетью, JSON, криптографией и другими аспектами, необходимыми для разработки агентов.
- Профилирование: Инструменты, такие как pprof, позволяют эффективно отслеживать и устранять утечки памяти и горутин.
🙅 Минусы:
— Мало библиотек для ML
— Нет "магии" как у Python-экосистемы
Но если тебе важны надежность, скорость и контроль, Go — это отличный выбор 🔥
📖 Читать полностью
🌀 Middleware и RoundTripper в Go: гибкая обработка HTTP-запросов
В Go нет встроенного понятия "middleware", как в других фреймворках — но вы можете легко реализовать его сами, особенно в контексте
🔧 RoundTripper — это интерфейс, который обрабатывает HTTP-запросы на уровне клиента (`http.Client`). Это даёт возможность внедрять логику *до* и *после* отправки запроса.
🧱 Пример: логгер запросов
📦 Использование:
💡 Таким образом, вы можете создавать middleware прямо внутри
• логирование
• кэширование
• модификация заголовков
• retry-логика
• трейсинг
🔗 Подробнее: dev.to/calvinmclean/middleware-and-roundtrippers-in-go-30pa
#golang #httpclient #middleware #webdev #devtools
В Go нет встроенного понятия "middleware", как в других фреймворках — но вы можете легко реализовать его сами, особенно в контексте
http.RoundTripper
.🔧 RoundTripper — это интерфейс, который обрабатывает HTTP-запросы на уровне клиента (`http.Client`). Это даёт возможность внедрять логику *до* и *после* отправки запроса.
🧱 Пример: логгер запросов
type LoggingRoundTripper struct {
rt http.RoundTripper
}
func (l *LoggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
log.Printf("📤 Запрос: %s %s", req.Method, req.URL)
resp, err := l.rt.RoundTrip(req)
if err == nil {
log.Printf("📥 Ответ: %d", resp.StatusCode)
}
return resp, err
}
📦 Использование:
client := &http.Client{
Transport: &LoggingRoundTripper{rt: http.DefaultTransport},
}
💡 Таким образом, вы можете создавать middleware прямо внутри
http.Client
, например:• логирование
• кэширование
• модификация заголовков
• retry-логика
• трейсинг
🔗 Подробнее: dev.to/calvinmclean/middleware-and-roundtrippers-in-go-30pa
#golang #httpclient #middleware #webdev #devtools
This media is not supported in your browser
VIEW IN TELEGRAM
Раньше: многоэтапные собеседования и тестовые
Сейчас: возможность получить оффер за один день!
Сбер зовёт Go-разработчиков на One Day Offer — он пройдёт 21 июня в онлайн-формате. Команда ищет будущих коллег в рекламную платформу SberAds сразу в несколько продуктов:
— Медийная реклама
— Performance Ads
— Инструменты разработки
— RTS
Регистрируйтесь на One Day Offer и будьте готовы к карьерным изменениям и работой над действительно масштабными задачами!
Сейчас: возможность получить оффер за один день!
Сбер зовёт Go-разработчиков на One Day Offer — он пройдёт 21 июня в онлайн-формате. Команда ищет будущих коллег в рекламную платформу SberAds сразу в несколько продуктов:
— Медийная реклама
— Performance Ads
— Инструменты разработки
— RTS
Регистрируйтесь на One Day Offer и будьте готовы к карьерным изменениям и работой над действительно масштабными задачами!