# NATS и JetStream: сообщения между сервисами

Девять практических опытов с настоящим NATS server и Node.js-клиентами. Публичная мастерская показывает **сохранённые события реального выполнения** на Windows и Linux. Кнопки в браузере воспроизводят шаги и переключают записи; браузер не подключается к брокеру и не создаёт новую доставку.

## Что проверяет стенд

1. Core pub/sub: одно событие получают две активные подписки.
2. Request/reply: ответ сервиса и реальный отказ при отсутствии responder.
3. Queue group: двенадцать задач распределяются между двумя подписками; пропорция не гарантирована.
4. File stream: три события получают PubAck и сохраняются до подключения читателя.
5. Pull consumer: сообщение получено, ackAck подтверждён, num_ack_pending сброшен.
6. Повторная доставка: nak с задержкой 150 мс приводит к повтору того же sequence.
7. Дедупликация: повтор msgID в пределах 120 секунд не увеличивает число сохранённых сообщений.
8. Replay: независимый durable consumer читает три события истории.
9. Обратное давление: max_ack_pending=2 блокирует третью выдачу до подтверждения.

В src/capture.mjs выполняются 16 утверждений результатов. Тестовые подписки используют одно подключение в одном процессе Node; это проверка механизмов доставки, не отказов нескольких физических серверов. При выполнении создаются потоки с уникальным LAB_-префиксом. В finally удаляются только созданные этим запуском streams и выполняется drain подключения. Клиент разрешает только изолированные адреса nats://127.0.0.1:14222 и nats://nats:4222.

## Зависимости

Сервер: nats:2.15.3-alpine. Node-пакеты: @nats-io/transport-node 3.4.0 и @nats-io/jetstream 3.4.0. Точный набор npm-зависимостей — в package-lock.json. Проект объявляет Node >=22; для повторения проверенной среды используйте Node 24 LTS. В записи Windows использован Node 24.19.0, а Linux-клиент собран с Node 24.22.2; базовый образ Dockerfile закреплён точным digest. Лицензии перечислены в THIRD-PARTY-LICENSES.txt. Брокер запускается в Linux-контейнере на обеих платформах; «Windows» в записи означает клиент Node на Windows.

## Windows / PowerShell

Установите Node 24 LTS, Docker Desktop с Linux-контейнерами и Compose. Распакуйте архив, откройте PowerShell в его каталоге. Не используйте порт или брокер существующего проекта: стенд предполагает собственный Compose project.

```powershell
node --version
docker compose version
npm ci --ignore-scripts --no-audit --no-fund
docker compose -p aen-nats-lab up -d nats
docker compose -p aen-nats-lab logs --tail=30 nats
Invoke-RestMethod http://127.0.0.1:18222/healthz
npm run capture
npm run serve
```

Дождитесь сообщения готовности сервера в логе и успешного healthz перед capture. Compose depends_on не является проверкой готовности брокера. Если первая проверка пришлась на запуск, повторите её после готовности; не объявляйте недоступность успешным выполнением.

Мастерская: http://127.0.0.1:8544. Брокер: 14222, HTTP-мониторинг: 18222, оба опубликованы только на 127.0.0.1. Остановить локальный статический сервер — Ctrl+C. Готовые записи уже включены в public, поэтому для их просмотра Docker не нужен: достаточно npm run serve, использующего стандартные модули Node. Кнопка полного ZIP предназначена для установленной мастерской на сайте; распакованный архив уже находится у вас.

После capture обновится public/recording.json. Переданный NATS_URL можно задать через $env:NATS_URL, но произвольный сервер адаптер не принимает. Это намеренная защита от запуска учебных операций в чужой инфраструктуре. Не убирайте её ради подключения к production.

## Linux / Bash

Локальный Node-клиент запускается аналогично. Переменная среды задаётся в синтаксисе Bash, зависимости устанавливаются отдельно для Linux.

```bash
npm ci --ignore-scripts --no-audit --no-fund
docker compose -p aen-nats-lab up -d nats
docker compose -p aen-nats-lab logs --tail=30 nats
curl --fail http://127.0.0.1:18222/healthz
NATS_URL=nats://127.0.0.1:14222 npm run capture
npm run serve
```

Можно выполнить клиент в Linux-контейнере из Compose. Этот способ подходит и Windows с Docker Desktop. Контейнер клиента обращается к сервису nats по внутреннему имени; опубликованный порт хоста ему не нужен.

```bash
docker compose -p aen-nats-lab build linux
docker compose -p aen-nats-lab run --rm linux
```

Результат появится в public/recording-linux.json через bind mount. На Linux учитывайте UID процесса контейнера и права каталога public: не делайте весь проект world-writable ради одного файла. Если файл получился принадлежащим root, измените владельца конкретного созданного файла на пользователя проекта, понимая происхождение файла. Изменять UID образа без проверки прав bind mount не требуется для знакомства со стендом.

## Что означает запись

PubAck сообщает о принятии сообщения JetStream; ack/ackAck относятся к состоянию consumer. Устойчивая запись заказа в базу — третье событие. Они не образуют общую транзакцию автоматически. Core NATS не хранит сообщение для отключённого подписчика. JetStream может повторить доставку, поэтому внешние действия требуют идемпотентности.

В шестом опыте повтор вызван **nak**, а не искусственно потерянным ack. В записи нет испытания падения процесса, отказа сети, перезапуска брокера или отказоустойчивого кластера. Сохранение в File storage одного брокера не является HA. Queue group может распределить 12 задач не поровну — это не ошибка теста. Replay использует отдельный consumer и Limits retention; подтверждение shipping не удаляет событие из потока.

## Очистка собственного стенда

Завершите только свой статический сервер через Ctrl+C. Следующая команда останавливает контейнеры выбранного лабораторного проекта и сохраняет именованный volume:

```bash
docker compose -p aen-nats-lab down
```

Для осознанного удаления **учебных** сохранённых данных этого проекта можно отдельно выполнить down -v. Не используйте docker system prune, не останавливайте Docker целиком, если им пользуются другие проекты, и не передавайте чужое имя Compose project. При повторном создании контейнера без удаления volume файловое хранилище остаётся, однако capture сам удаляет свои временные streams при завершении.

## Перенос в приложение

Начните с одного события с устойчивым event_id и версией схемы. Создайте поток и consumer административным инструментом, выдайте приложению узкие права на нужные subjects. Подтверждайте сообщение после устойчивого результата обработки. Перед настройкой VPS прочитайте LINUX-VPS.md: там отдельно разобраны auth, TLS, закрытый мониторинг, volume, восстановление и ручное упражнение с restart. Учебный nats.conf без авторизации не является production-конфигурацией.
