Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 3 из 25 ~18 мин +20 XP

Подключение amqp091-go: первый клиент

Подключение amqp091-go — первый шаг кода к живому брокеру: в этом уроке ставим библиотеку, открываем соединение amqp.Dial, разбираем URL подключения по частям и учимся отличать connection refused от отказа авторизации. Клиент получится минимальным, но честным — с таймаутом, обработкой ошибок и без пароля в логах.

Содержание урока · 10 разделов

Брокер из второго урока отвечает на /api/overview, но ваш Go-код ещё не умеет с ним разговаривать: закрываем эту дыру. План урока простой и повторяется в каждом библиотечном проекте: объявить модуль, добавить зависимость, открыть соединение и проверить, что оно живое. Звучит скучно ровно до первого инцидента, когда выясняется, что «просто Dial» без таймаута вешает старт сервиса на несколько минут, а пароль из строки подключения оседает в логах CI. Поэтому первый клиент мы напишем сразу во взрослом виде: с контекстом таймаута, честной обработкой ошибок и пониманием, что именно происходит на проводе, пока функция притворяется мгновенной. Очереди, публикации и потребители пойдут следом — сначала фундамент. Если брокера под рукой нет, вернитесь к установке RabbitMQ в Docker и держите контейнер запущенным: каждая строка этого урока стучится в localhost:5672.

Подключение amqp091-go: go get и импорт#

Начинается подключение amqp091-go как всегда: go mod init example.com/orderservice, затем go get github.com/rabbitmq/amqp091-go. Библиотека прописывается в go.mod, а в коде импортируется с алиасом: import amqp "github.com/rabbitmq/amqp091-go" — алиас нужен, потому что имя пакета внутри репозитория не совпадает с последним сегментом пути, и без него каждый импорт тянет за собой длиннющий префикс. Конвенция сообщества железная: пакет по-прежнему зовётся amqp, поэтому код со streadway/amqp и современный код выглядят одинаково — меняется только строка импорта. Версии библиотеки живут в первой мажорной линии: миграции между ними почти незаметны, но changelog стоит читать при обновлении, особенно если опираетесь на поведение контекста в публикациях. Всё, что делает библиотека, — перевод Go-вызовов в кадры протокола AMQP 0-9-1 и обратно, без магии и генерации кода: сигнатуры повторяют команды брокера, и это делает amqp go клиент лучшим учебником самого протокола.

Обновление зависимости и что смотреть в changelog#

Зависимость ставится один раз, а живёт долго, поэтому пара слов про обновления. Команда go get github.com/rabbitmq/amqp091-go@latest поднимает версию до самой свежей, go list -m -versions github.com/rabbitmq/amqp091-go показывает весь список доступных тегов, а точную версию фиксируют через собаку с номером — приём полезный, когда changelog между версиями важнее новизны. В go.sum попадают контрольные суммы модулей: это защита от подмены зависимости, и отключать её не стоит. При апгрейде я смотрю на три вещи: не поменялись ли сигнатуры вызовов с контекстом, не устарел ли используемый метод — библиотека честно помечает такие в комментариях, — и что случилось с таймаутами по умолчанию. Мажорных перестроек у amqp091-go не было: API стабилен с момента переезда под организацию RabbitMQ, и это одна из причин выбрать именно его. В проекте с несколькими брокерами зависимость всё равно одна: разные адреса — это данные конфигурации, а не отдельный код.

Первый клиент: Dial и Close

GO
package main

import (
        "log"

        amqp "github.com/rabbitmq/amqp091-go"
)

func main() {
        url := "amqp://guest:guest@localhost:5672/"

        conn, err := amqp.Dial(url)
        if err != nil {
                log.Fatal(err)
        }
        defer conn.Close()

        log.Println("соединение установлено:", !conn.IsClosed())
}

Минимальный amqp go клиент умещается в пятнадцать строк: amqp.Dial открывает TCP-соединение, договаривается о параметрах протокола и возвращает *amqp.Connection, готовую к работе. Ошибка обрабатывается до любых других шагов — без брокера делать дальше нечего, поэтому честнее упасть сразу. defer conn.Close() освобождает соединение при выходе, а conn.IsClosed() даёт быструю проверку состояния. Пока это всё; каналы и очереди — вопросы следующих уроков.

URL подключения по частям#

Строка amqp://guest:guest@localhost:5672/ — не произвольный текст, а полный адрес с правами доступа, и читать её стоит как конверт. Схема amqp задаёт протокол и шифрование: amqps вместо неё означает «тот же протокол поверх TLS» и другой порт по умолчанию. Дальше учётные данные до собачки — логин и пароль, которые брокер проверит на этапе аутентификации; пароль со спецсимволами URL-кодируется, иначе строка развалится на части. Хост и порт говорят, куда идти: localhost:5672 для локального контейнера, 5671 для TLS. Завершает адрес путь к vhost — виртуальному пространству имён брокера из прошлого урока; пустой путь после порта равен корневому vhost со слэшем. Один нюанс, на котором спотыкаются: vhost / в URL записывается как /, а vhost с именем production — как /production; когда vhost не существует, Dial падает с ошибкой доступа, и не факт, что вы поймёте это без чтения логов брокера.

Анатомия строки подключения#

ФрагментЧто значитТиповая ошибка
amqp://протокол без шифрованияamqps против открытого порта брокера
guest:guest@логин и пароль для аутентификациипароль в git и логах CI
localhost:5672хост и AMQP-порт брокера5672 вместо 15672 — порт панели
/путь к vhost, по умолчанию корневойvhost не создан — отказ доступа
amqps://…:5671то же поверх TLSTLS без доверия к сертификату

Что происходит внутри amqp.Dial#

amqp.Dial выглядит как одна строка, но под ней прогоняется весь протокольный танец AMQP 0-9-1. Сначала обычное TCP-подключение к хосту и порту — здесь рождаются ошибки вида connection refused, когда на порту никто не слушает. Клиент и сервер обмениваются заголовками протокола и приходят к согласию о версии AMQP 0-9-1. Затем сервер предлагает параметры безопасности, клиент отвечает учётными данными из URL — так появляется отказ авторизации при неверной паре. Потом стороны договариваются о рамках соединения: максимальный размер кадра, число каналов и интервал heartbeat, по которому обе стороны будут проверять живость друг друга. Только после этого Dial возвращает управление с готовым объектом соединения. Из этого следует практическое правило: Dial блокируется до полной готовности брокера, поэтому таймаут на него — не украшение, а страховка от зависшего старта сервиса. Как устроены соединения и каналы после рукопожатия — тема следующего урока.

Таймаут подключения через DefaultDial

GO
conn, err := amqp.DialConfig(url, amqp.Config{
        Dial: amqp.DefaultDial(5 * time.Second),
})
if err != nil {
        log.Fatal(err)
}
defer conn.Close()

DialConfig принимает amqp.Config, а поле Dial — это функция открытия сетевого соединения. amqp.DefaultDial оборачивает стандартный net.DialTimeout в нужную обёртку: попытка длится не дольше пяти секунд, после чего возвращается ошибка таймаута. Пять секунд — рабочий компромисс: меньше — ложно падает на медленной сети, больше — сервис зависает на старте с мёртвым брокером. Точную настройку heartbeat и свойств клиента аналогично делают в том же Config.

Ошибки первого запуска: refused, auth, timeout#

Три ошибки встретят вас раньше всех остальных, и различать их стоит по месту возникновения. Connection refused — TCP-уровень: по этому адресу никто не слушает, значит контейнер не поднят, порт не проброшен или хост неверный. Отказ авторизации — уже после TCP и рукопожатия: брокер отвергает пару логин-пароль или не пускает guest из сети; причину ищите в docker logs rabbitmq, там она прописана словами. Таймаут — самый коварный вариант: соединение молчит до предела, обычно виноваты файрвол, security group в облаке или опечатка в хосте, которая уехала в другую сеть. Диагностика идёт слоями: сначала telnet или nc на порт — отвечает ли вообще; затем логи брокера — доходит ли до аутентификации; и только потом код. Если соединение живёт, но рвётся в работе — это история про heartbeat и восстановление соединения, к ней вернёмся с рабочим кодом в руках.

Чек-лист первого клиента#

  • go.mod содержит github.com/rabbitmq/amqp091-go после go get.
  • Строка подключения приходит из переменной окружения, а не из исходника.
  • У amqp.Dial есть таймаут через amqp.DefaultDial — старт не может зависнуть навсегда.
  • Ошибка Dial обрабатывается фейл-фастом: без брокера сервис не должен продолжать.
  • defer conn.Close() стоит сразу после успешного подключения.
  • В логи пишутся хост, порт и пользователь — но никогда не пароль.

Соединение есть — самое время проверить его под нагрузкой. В следующем уроке разберём, почему поверх одного TCP-соединения открывают много каналов, где у этой модели лимиты и почему канал привязывают к одной горутине. Проверку соединения в тестах, кстати, делают тем же Dial: локальный брокер из Docker поднимается за секунды, а табличные тесты с ним уже дают интеграционную уверенность без моков. Держите в голове и обратную сторону: тест против живого брокера требует окружения, поэтому unit-тесты логики пишут без сети — к этой теме вернёмся ближе к концу курса. А если хочется увидеть сообщения своими глазами раньше четвёртого урока — закройте соединение и посмотрите в management UI: Connections покажет пустоту, и вы сразу почувствуете, за чем следит IsClosed.

Проверка: что делает Dial

Что обязан сделать amqp.Dial перед тем, как вернуть соединение?

Проверка: vhost в URL

Как выглядит строка подключения к vhost с именем production на локальном брокере?

Что выведет программа?

Прочитайте код и выберите, что он выведет:

conn, err := amqp.Dial(
        "amqp://guest:guest@127.0.0.1:5672/")
if err != nil {
        fmt.Println("dial:", err)
        return
}
defer conn.Close()

fmt.Println("ok")

Соберите подключение с таймаутом

Допишите вызов DialConfig, конструктор таймаута и закрытие соединения.

conn, err := amqp.(url, amqp.Config{ Dial: amqp.(5 * time.Second), }) if err != nil { log.Fatal(err) } defer conn.()

Соберите первый клиент по строкам

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

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Карточки: первый клиент

Термин

amqp091-go

нажмите, чтобы перевернуть
Определение

Официальный клиент RabbitMQ для Go. Импортируется с алиасом: import amqp "github.com/rabbitmq/amqp091-go".

1 / 6

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Вывод

Запустите код, чтобы увидеть вывод.

Коротко: что запомнить

  • go get github.com/rabbitmq/amqp091-go и алиас amqp — конвенция, общая для всей экосистемы.
  • URL подключения: схема, учётные данные, хост с портом и путь к vhost.
  • amqp.Dial прогоняет рукопожатие AMQP 0-9-1 целиком и блокируется до готовности брокера.
  • Таймаут ставят через amqp.DialConfig и amqp.DefaultDial — старт сервиса не должен висеть вечно.
  • Connection refused, отказ авторизации и таймаут диагностируются слоями: TCP, потом логи брокера, потом код.
  • Пароль живёт в переменных окружения и никогда не попадает в логи.

Домашнее задание

Соберите модуль orderservice с amqp091-go: подключайтесь к брокеру из переменной окружения RABBITMQ_URL с таймаутом пять секунд, печатайте состояние IsClosed и доведите до ошибки connection refused, остановив контейнер. Потом запустите брокера снова и убедитесь, что клиент подключается без правок кода.

Личные заметкиПусто
Хранятся только в вашем браузере (RabbitMQ · Подключение amqp091-go: первый клиент)

Вопросы и ответы по уроку

Нужен ли отдельный пакет для аутентификации в amqp091-go?

Нет: логин и пароль передаются прямо в URL подключения, и Dial передаёт их брокеру на этапе согласования безопасности. Для особых схем аутентификации у amqp.Config есть поле SASL, но в типовом проекте достаточно пары user:pass в строке подключения.

Почему Dial зависает, хотя брокер вроде доступен?

Без явного таймаута Dial упирается в таймауты операционной системы, которые на сетевых проблемах тянут минуты. Ставьте amqp.DefaultDial с разумным пределом — единицы секунд; если соединение не прошло за это время, значит проблема в сети, файрволе или адресе, а не в коде.

Куда деть пароль, если URL нельзя коммитить?

В переменную окружения или в файл конфигурации вне git, а в compose-файле — в environment сервиса. В логах печатайте только хост, порт и имя пользователя; сами ошибки amqp.Dial пароль не раскрывают, но строку подключения целиком логировать всё равно не стоит.

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Следующая ступень учебного пути

Excelize25 уроков~10 чпрактика25 уроков уже доступны

Excel в Go: чтение и генерация xlsx на excelize

Курс excelize на Go: создание xlsx, чтение, стили, формулы, диаграммы и StreamWriter для больших файлов. 25 уроков с примерами кода и проектом.

  • Создавать и читать xlsx-файлы средствами excelize
  • Работать с листами, ячейками, строками и столбцами
  • Оформлять таблицы: стили, шрифты, границы, форматы чисел и дат
  • Вставлять формулы, диаграммы и изображения