Взаимодействие Orchestrator и RDP2 через MQTT
Доступно с версии 1.25.9+
Реализован новый событийный метод взаимодействия между службами Orchestrator (WebApi) и RDP2 через протокол MQTT-over-WebSockets с использованием RabbitMQ в качестве брокера сообщений. Этот подход решает задачи масштабирования системы и снижает нагрузку при управлении большим количеством RDP-сессий.
Преимущества MQTT-over-WebSockets
- WebApi стал работать в двух режимах одновременно, обеспечивая обратную совместимость со старыми версиями RDP2 по HTTP и поддерживая новый режим по MQTT.
- RDP2 можно переключить в новый режим работы через конфигурационный файл с последующим перезапуском службы.
- Взаимодействие включает обмен сообщениями о статусах сессий, команды на завершение и уведомления о состоянии служб.
Сравнение методов взаимодействия
1. Действующий метод: взаимодействие через REST API
Служба RDP2 периодически опрашивает WebApi с помощью REST-запросов для получения списка сессий и отправки их статусов.
Цикл обработки сессий через REST API:
Основные операции:
-
GET
/api/RdpSessions?addressFilter={filterString}
→ Получение списка сессий для обработки -
PUT
/api/RdpSessions/UpdateConnectionStatuses
→ Отправка обновленных статусов сессий -
GET
/api/RdpSessions/CheckNoRdpPeriods?addressFilter={filterString}
→ Инициация проверки периодов простоя -
PUT
/api/RdpSessions/{id}/SetNeedForLogOffRDPSessionUser
→ Команда на завершение сессии RDP
2. Новый метод: взаимодействие по протоколу MQTT-over-WebSockets
Взаимодействие построено на обмене сообщениями через шину RabbitMQ.
- WebApi публикует команды и данные о сессиях (например, создать сессию).
- RDP2 подписывается на соответствующие темы, выполняет команды и публикует статусы сессий и служебные уведомления.
1. Уведомление о состоянии службы RDP2 (RdpServiceNoticeMessage
)
При запуске или остановке служба RDP2 отправляет сообщение RdpServiceNoticeMessage
:
/// <summary>
/// Уведомление о состоянии службы RDP2
/// </summary>
public class RdpServiceNotice
{
/// <summary>
/// Фильтр адресов обслуживаемых машин (пусто = все доступные адреса)
/// </summary>
public string AddressFilter { get; set; }
/// <summary>
/// IP-адрес машины со службой RDP2
/// </summary>
public string Host { get; set; }
/// <summary>
/// Флаг запуска/останова службы RDP2.
/// </summary>
public bool IsStarted { get; set; }
}
Процесс обработки уведомлений службы RDP2:
- RDP2 публикует
RdpServiceNoticeMessage
при старте/остановке - WebApi сохраняет информацию в таблицу
Rdp2AddressFilters
- WebApi отправляет полный список сессий для данной службы RDP2
- WebApi отправляет список через сообщение
RdpSessionDataMessage
Модель данных сессии RDP
public class RdpSessionData
{
public int Id { get; set; }
/// <summary>Имя RDP-пользователя (административное)</summary>
public string AdminName { get; set; }
/// <summary>Имя RDP-пользователя</summary>
public string UserName { get; set; }
/// <summary>Пароль пользователя</summary>
public string Password { get; set; }
/// <summary>IP-адрес удаленного компьютера</summary>
public string Address { get; set; }
/// <summary>Активна ли пауза без сессий роботов</summary>
public bool IsNoRdpPause { get; set; }
/// <summary>Требуется ли пауза без сессий роботов</summary>
public bool NeedNoRdpPause { get; set; }
/// <summary>Длительность паузы в секундах</summary>
public int NoRdpPauseDurationInSeconds { get; set; } = 60;
/// <summary>Поддерживать RDP-сессию постоянно</summary>
public bool KeepRdpSession { get; set; }
public bool UserProfileLoaded { get; set; }
public int AuthenticationLevel { get; set; }
public bool NegotiateSecurityLayer { get; set; }
public bool EnableCredSspSupport { get; set; }
/// <summary>Параметры подключения</summary>
public int DesktopWidth { get; set; }
public int DesktopHeight { get; set; }
public int ColorDepth { get; set; }
/// <summary>Статус подключения</summary>
public bool Connected { get; set; }
public DateTime? ConnectedChangedAt { get; set; }
public DateTime? ConnectedUpdatedAt { get; set; }
public int WorkerId { get; set; }
public int? RdpPort { get; set; }
/// <summary>Принудительное поддержание сессии (только Windows RDP)</summary>
public bool? ForceKeepRdpSession { get; set; }
}
3. Управление сессиями через шину сообщений
Распределение сессий:
- WebApi отправляет
RdpSessionDataMessage
с сессиями для конкретной службы RDP2 - RDP2 сохраняет сессии во внутреннем кэше
Мониторинг и управление:
- RDP2 регулярно проверяет состояние сессий из кэша
- Автоматически запускает/останавливает сессии по необходимости
- Публикует статусы сессий после каждого цикла проверки
4. Команда на завершение сессии (RdpSetNeedForLogoffMessage
)
После обработки сессий RDP2 отправляет RdpSessionStatusesMessage
:
/// <summary>
/// Статус RDP-сессии
/// </summary>
public sealed class RdpSessionStatus
{
/// <summary>ID сессии</summary>
public int SessionId { get; set; }
/// <summary>Статус подключения</summary>
public bool Connected { get; set; }
/// <summary>Время изменения статуса подключения</summary>
public DateTime ConnectedChangedAt { get; set; }
/// <summary>Время последнего обновления статуса</summary>
public DateTime ConnectedUpdatedAt { get; set; }
}
Настройка нового метода взаимодействия
Для перевода взаимодействия между WebApi и RDP2 на новый режим требуется выполнить следующие шаги:
Шаг 1: Настройка RabbitMQ
На сервере с установленным RabbitMQ выполните следующие команды (для Windows — в C:\Program Files\RabbitMQ Server\rabbitmq_server-<Версия>\sbin
)
rabbitmq-plugins enable rabbitmq_mqtt
rabbitmq-plugins enable rabbitmq_web_mqtt
Настройка брандмауэра: Откройте TCP-порт 15675
, который используется для MQTT-over-WebSockets.
Шаг 2: Настройка NGINX
Добавьте в конфигурационный файл nginx.conf
блок для проксирования MQTT-трафика.
http {
...
upstream mqtt {
server <IP_или_имя_сервера_RabbitMQ>:15675;
}
server {
...
location /mqtt/ {
proxy_pass http://mqtt;
rewrite ^/mqtt/(.*)$ /$1 break;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
...
}
}
Проверьте конфигурацию:
nginx -t
в случае отсутствия ошибок, перезапустите службу NGINX:
nginx -s reload
Шаг 3: Настройка службы WebApi
В конфигурационном файле appsettings.Production.json
(или другом актуальном) добавьте раздел Mqtt
.
{
...,
"Mqtt": {
"Url": "wss://<IP или имя и порт сервера NGINX>/mqtt/ws",
"Username": "<пользователь RabbitMQ>",
"Password": "<(зашифрованный) пароль пользователя RabbitMQ>"
},
...
}
Важно: WebApi начнет работать в двух режимах одновременно, отправляя сообщения в шину и продолжая отвечать на REST-запросы от старых версий RDP2.
Шаг 4: Настройка службы RDP2
В конфигурационном файле службы RDP2 (appsettings.Production.json
) добавьте аналогичный раздел Mqtt
.
{
...,
"Mqtt": {
"Url": "wss://<IP или имя и порт сервера NGINX>/mqtt/ws",
"Username": "<пользователь RabbitMQ>",
"Password": "<(зашифрованный) пароль пользователя RabbitMQ>"
},
...
}
Проверка работоспособности
- Убедитесь, что службы RabbitMQ и NGINX запущены.
- Перезапустите службы WebApi и RDP2.
- В логах RDP2 при запуске должно быть сообщение об успешном подключении к MQTT-брокеру и публикации уведомления
RdpServiceNoticeMessage
. В логах WebApi должно быть сообщение о получении уведомленияRdpServiceNoticeMessage
от службы RDP2. - В интерфейсе Orchestrator статусы RDP-сессий должны обновляться без задержек.
Для работы MQTT необходимо наличие раздела Mqtt с корректным значением Url. При отсутствии этих настроек система автоматически переходит на взаимодействие через REST API.
Возврат к REST API
При проблемах с MQTT временно удалите раздел Mqtt
из конфигурации для возврата к старому методу.