Библиотека Go (Golang) разработчика
Библиотека Go (Golang) разработчика
1 972 подписчиков · @golang_lib
К каналу →
📦 go mod: Хватит удалять go.sum, когда что-то сломалось Управление зависимостями в Go выглядит элегантно: написал import, сделал go mod tidy, и всё работает. Но стоит случиться ко…
Читать далее →
755
Реклама
🔄 Идемпотентность: Как не списать деньги дважды при ретраях Худшее, что может сделать ваш микросервис, это упасть с пятисоткой. Нет, вру. Худшее, это тихо выполнить операцию дважд…
Читать далее →
567

📜 Паттерн Saga: Как откатить то, что откатить нельзя Представьте классическую задачу: клиент нажимает кнопку «Купить ту

📜 Паттерн Saga: Как откатить то, что откатить нельзя

Представьте классическую задачу: клиент нажимает кнопку «Купить тур». Вашему бэкенду нужно сделать три вещи:

1. Забронировать рейс (через API авиакомпании).
2. Забронировать отель (через микросервис отелей).
3. Списать деньги (через платежный шлюз).

В монолите с одной базой вы бы просто открыли транзакцию BEGIN ... COMMIT и спали спокойно. Но у нас микросервисы. Вы не можете повесить лок на базу данных авиакомпании.

Что если рейс забронирован, отель подтвержден, а на карте клиента нет денег? Вы не можете просто сказать ROLLBACK. Рейс уже куплен. Вы потеряли деньги компании.

Здесь на сцену выходит Паттерн Saga.

Суть Саги: Распределенная транзакция разбивается на серию локальных. И самое главное: для каждого шага (Execute) вы обязаны написать шаг отмены (Compensate).

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

В архитектуре есть два пути: Хореография (микросервисы кидаются событиями через Kafka) и Оркестрация (один сервис управляет всем). В Go элегантнее всего пишется Оркестратор.

Реализация Оркестратора на Go:

type SagaStep struct {
Name string
Execute func(ctx context.Context) error
Compensate func(ctx context.Context) error
}

func RunSaga(ctx context.Context, steps []SagaStep) error {
var completedSteps []SagaStep

// 1. Идем вперед
for _, step := range steps {
err := step.Execute(ctx)
if err == nil {
completedSteps = append(completedSteps, step)
continue
}

log.Printf("Ошибка на шаге %s: %v. Начинаем откат...", step.Name, err)

// 2. Ошибка! Идем назад и откатываем
for i := len(completedSteps) - 1; i >= 0; i-- {
rollbackStep := completedSteps[i]
if compErr := rollbackStep.Compensate(ctx); compErr != nil {
// Это катастрофа. Подробнее в Senior Tips.
log.Printf("КРИТИЧЕСКАЯ ОШИБКА отката %s: %v", rollbackStep.Name, compErr)
}
}
return fmt.Errorf("saga failed on step %s: %w", step.Name, err)
}

return nil
}

Как это выглядит при вызове:

steps := []SagaStep{
{
Name: "BookFlight",
Execute: func(ctx context.Context) error { return flightAPI.Book(userID) },
Compensate: func(ctx context.Context) error { return flightAPI.Cancel(userID) },
},
{
Name: "BookHotel",
Execute: func(ctx context.Context) error { return hotelAPI.Book(userID) },
Compensate: func(ctx context.Context) error { return hotelAPI.Cancel(userID) },
},
// ... и так далее
}

err := RunSaga(ctx, steps)


🔥 Нюансы:

1. Компенсации не имеют права падать. Если функция Execute упала, это нормально (нет денег на карте, сеть моргнула). Но если упала функция Compensate (не смогли отменить бронь отеля) - ваша система переходит в неконсистентное состояние. Отель ждет гостя, а клиент ничего не оплатил.
Решение: Компенсирующие действия должны отправляться в надежную очередь (Dead Letter Queue) и ретраиться до посинения (или до вмешательства саппорта).

2. Идемпотентность - царица Саги.
Так как функции компенсации могут ретраиться бесконечно, они обязаны быть идемпотентными (вспоминаем прошлый пост!). Если мы 5 раз вызовем hotelAPI.Cancel, бронь должна отмениться один раз, а остальные 4 вызова должны вернуть 200 OK.

3. Грязное чтение (Lack of Isolation).
Сага не обладает свойством "I" из ACID (Изоляция). Между бронированием отеля и списанием денег могут пройти секунды. В этот момент другой сервис может увидеть, что отель забронирован. Если сага откатится, другой сервис останется с неверными данными. Учитывайте это при проектировании (например, вводите статусы PENDING).

Сага - это сложно. Не тяните её в проект, пока можете обойтись одной таблицей в монолите. Но если уж распределили базу, будьте готовы платить за это кодом.

👉 @golang_lib
🔌 Circuit Breaker: Как не добить лежачего (и не умереть самому) Знакомая ситуация: внешний сервис (например, процессинг платежей или тяжелая аналитика) начинает тормозить. Ваши за…
Читать далее →
502
Connection Pool: Как Go убивает базу данных (и как этого избежать) Выкатываете вы новый сервис, запускаете нагрузочное тестирование, и тут логи начинают истекать кровью: FATAL: so…
Читать далее →
484
Другие главы канала «Библиотека Go (Golang) разработчика»
Выберите главу, чтобы продолжить чтение
Все посты →
Глава от 04.08.2026
🌊 io.Reader и io.Writer: Лего для взрослых (и спасение от OOM) Знакомый сценари…
👁 243 просмотров
Глава от 30.07.2026
Как спасти сборщик мусора от перегрева: используем sync.Pool 🛟 В продолжение те…
👁 304 просмотров
Глава от 22.07.2026
Базовый стек межсервисного взаимодействия и наблюдаемости: HTTP(S), gRPC, Protob…
👁 384 просмотров
Глава от 22.07.2026
🚀 PGO: Как получить +10% к скорости, не написав ни строчки кода Все мы любим оп…
👁 307 просмотров
Глава от 21.07.2026
🚀 Базовые паттерны проектирования в Go: Пишем чистый код Go не является классич…
👁 325 просмотров
Глава от 11.07.2026
⚙️ Go Runtime изнутри: GMP, GC, escape analysis и memory model Почему Go "прост…
👁 398 просмотров
Глава от 08.07.2026
🕳 context.Context: Хватит превращать контекст в мусорное ведро Мы передаем ctx …
👁 378 просмотров
Глава от 01.07.2026
Куда уходит память? Разбираемся с Escape-анализом в Go 🚀 Многие любят Go за вст…
👁 414 просмотров
Глава от 30.06.2026
🔀 Fan-Out / Fan-In: Строим конвейер, который не лопнет Представьте задачу: у ва…
👁 387 просмотров

Популярные посты канала «Библиотека Go (Golang) разработчика»

Хватит мучить sync.WaitGroup для HTTP-запросов Каждый джун проходит этот путь: 1. Запускаем 10 горутин через go func(). 2. Добавляем wg.Ad…
👁 859 просмотров
JSON быстрее, чем вы думаете Стандартный encoding/json в Go надежный, но... медленный. Он активно использует рефлексию, что бьет по CPU на …
👁 856 просмотров
"Семафор". Не убей базу данных Запустить 10,000 горутин в Go дешево. А вот открыть 10,000 коннектов к базе или внешнему API - дорого и боль…
👁 802 просмотров
🌪 Fuzzing: Ломаем свой код, пока это не сделали другие Мы привыкли писать Unit-тесты по принципу: "Я ожидаю, что если подать А, выйдет Б". …
👁 779 просмотров
Context Cancellation - это не kill -9 Одна из самых частых иллюзий у разработчиков, приходящих в Go: "Я вызвал cancel(), почему моя горутин…
👁 769 просмотров
🧪 Table-Driven Tests: Хватит плодить функции-клоны Проверяю PR джуниора. Файл на 500 строк, из них 450 - это тесты. Смотрю внимательнее, а …
👁 767 просмотров
Челлендж по обработке миллиарда строк на Go: от 1 минуты 45 секунд до 4 секунд Пару недель назад я прочитал о запавшем мне в душу челлендже…
👁 767 просмотров
📦 go mod: Хватит удалять go.sum, когда что-то сломалось Управление зависимостями в Go выглядит элегантно: написал import, сделал go mod tid…
👁 755 просмотров
🚀 PGO: Как получить +10% к скорости, не написав ни строчки кода Все мы любим оптимизировать. Переписываем мапы, пулим объекты в sync.Pool, …
👁 741 просмотров
🗑 Сборщик мусора в Go: Скрытый налог на ваш CPU Если вы спросите джуна, как работает память в Go, он ответит: "Ну, там есть GC, он сам всё …
👁 717 просмотров
🧩 Struct Padding: Как вы теряете гигабайты памяти на ровном месте Знаете это чувство, когда вы долго проектируете структуру, высчитываете т…
👁 703 просмотров
🧬 Generics: Как перестать писать Java на Go Мы ждали их 10 лет. И вот, когда они появились, код-ревью превратились в выставку угловых скобо…
👁 696 просмотров
🔄 Идемпотентность: Как не списать деньги дважды при ретраях Худшее, что может сделать ваш микросервис, это упасть с пятисоткой. Нет, вру. Х…
👁 567 просмотров
🔌 Circuit Breaker: Как не добить лежачего (и не умереть самому) Знакомая ситуация: внешний сервис (например, процессинг платежей или тяжела…
👁 502 просмотров
Connection Pool: Как Go убивает базу данных (и как этого избежать) Выкатываете вы новый сервис, запускаете нагрузочное тестирование, и тут …
👁 484 просмотров
Куда уходит память? Разбираемся с Escape-анализом в Go 🚀 Многие любят Go за встроенный сборщик мусора (GC) и простоту работы с указателями.…
👁 414 просмотров
⚙️ Go Runtime изнутри: GMP, GC, escape analysis и memory model Почему Go "просто работает" быстро без ручного управления потоками — разбира…
👁 398 просмотров
🔎 pprof: Как найти функцию, которая жрет 80% CPU Сервис на проде внезапно упирается в полку по процессору. Что делает новичок? Сидит и смо…
👁 388 просмотров
🔀 Fan-Out / Fan-In: Строим конвейер, который не лопнет Представьте задачу: у вас есть CSV-файл на 10 миллионов строк (или бесконечный стрим…
👁 387 просмотров
Базовый стек межсервисного взаимодействия и наблюдаемости: HTTP(S), gRPC, Protobuf и OpenTelemetry Современная микросервисная архитектура т…
👁 384 просмотров

Связанные темы в других каналах

Каналы из той же тематики, где часто появляются близкие сюжеты
Вся тема →
@canalmaxone
AntiCloudMod
AntiCloudMod — сообщество для тех, кто ценит свободу общения без облачной цензуры. Здесь обсуждают альтернативные мессенджеры, инструменты для приватности и децентрализов…
👥 394 427 · -11 335/7д
@BelgorodDRONE
Информация БПЛА Белгород, Белгородский район
7924148410
👥 195 093 · +3 326/7д
@biologia89
РОБЛОКС🔷
РОБЛОКС В МАКС! Реклама: https://clck.ru/3Tmmgx
👥 169 669 · +13 583/7д
@WylsacomRed
Wylsacom Red
Официальный канал Wylsacom в Max. Тут всё про технологии и жизнь в ногу со временем! Номер заявления для регистрации в РКН: № 6979154178 Розыгрыши: kichaev@wylsacom.med…
👥 161 832 · -278/7д
@TikTokModCloud
TikTokModCloud
Официальные обновления стабильного мода TikTok Чат: https://clck.ru/3S6mVh По рекламе: https://iimax.ru/dim4ugan
👥 118 868 · +1 265/7д
@na_kruchok
ГЛЕНТ | МЕМЫ
Глент мемы Это фан-сообщество, созданное преданными поклонниками для поддержки творчества Глента. Данный канал НЕ является официальным и ведется фанатом Биржа: telega.…
👥 76 534 · -757/7д
🏷 Темы и теги
#go разработка #оптимизация go #паттерны проектирования #golang #sync.pool #микросервисы #Технологии
📋 О канале Библиотека Go (Golang) разработчика
Погрузись в мир Golang с библиотекой полезных материалов: от лучших практик и обзоров библиотек до советов по оптимизации и реальных кейсов. Канал для тех, кто пишет на Go и хочет расти — без воды, только то, что реально пригодится в работе.
🔍 Архив всех постов Макс
Поиск по 15,699,001 постам из 203,272 каналов
Подключить за 490 ₽/мес →
Удалить пост или канал с МАКСОТЕКИ
Заявка подтверждается через бота Макс: нужно быть администратором канала и добавить бота МАКСОТЕКИ в администраторы. После проверки канал или конкретный пост скрывается с сайта.
📊 Аналитика канала «Библиотека Go (Golang) разработчика» ➡️ Перейти в канал Макс
Заявка в МАКСОТЕКА
Добавьте свой канал в каталог
Зарегистрируйтесь в личном кабинете и добавьте канал за пару кликов.
Перейти в личный кабинет →

Бесплатная регистрация, быстрая модерация.