Для взаимодействия с RabbitMQ необходимо реализовать два

advertisement
Информационное сопровождение. Инструкция по настройке
взаимодействия МИС с сервисами ТФ ОМС ЯО.
Система обмена сообщениями между участниками информационных систем построена на базе
платформы RabbitMQ, обеспечивающей высокую производительность и надежность
промышленного уровня, имеющей обширный набор компонентов по взаимодействию с ней.
(Подробней см. http://rabbitmq.com (описание платформы) и
http://www.rabbitmq.com/devtools.html (описание клиентов и инструментов разработчика).
Терминология
RabbitMQ — платформа, реализующая систему обмена сообщениями между компонентами
программной системы (Message Oriented Middleware) на основе стандарта AMQP (Advanced
Message Queuing Protocol).
МИС – медицинская информационная система
МО – медицинская организация ЯО, участвующая в процессе информационного взаимодействия
посредствам одного или нескольких участников информационного взаимодействия.
Участник информационного взаимодействия (УИВ) – компонент информационной системы МО,
представленный отдельной МИС.
Описание принципов взаимодействия
RabbitMQ реализует обменники (exchanges) и очереди (queues). Взаимодействие осуществляется
через обменник с именем TFOMS.Exchange, путем отправки сообщений в очередь ТФ ОМС ЯО с
именем TFOMS.Queue.7ADB0C1E-D488-4C2B-97FF-52D003FC47BD, и приемом сообщений из
очереди, соответствующего УИВ с именем TFOMS.Queue.{client_id}. Где client_id глобальный
уникальный идентификатор (GUID) УИВ. client_id назначается ТФ ОМС ЯО, каждому УИВ согласно
предоставленной из МО информации.
МО 1
RabbitMQ
ТФ ОМС
МИС1 (УИВ)
УИВ
МИС 2 (УИВ)
МО 2
Каждый УИВ имеет свой
уникальный client_id
МИС 1 (УИВ)
Рисунок 1. Общая схема информационного взаимодействия
УИВ 1 (МО 1)
ТФ ОМС
УИВ 2 (МО 2)
Публикация сообщения в очередь ТФ ОМС
Обработка входящего сообщения
Результат приема в очередь УИВ 1
Передача сообщения в МО 2 в очередь УИВ 2
Доставка сообщения
из МО 1 в МО 2
Обработка
Результат приема в очередь ТФ ОМС
Сообщение из ТФ ОМС в МО 1 в очередь УИВ 1
Обработка сообщения
Результат приема сообщения в очередь ТФ ОМС
Получение информации из ТФ ОМС
Рисунок 2. Концептуальная схема передачи и обработки сообщений
Соединение с RabbitMQ
Сервер RabbitMQ размещается в ТФ ОМС. Доступ к нему возможен только внутри защищенной
сети VipNET. Для определения IP адреса сервера RabbitMQ в сети VipNET каждому УИВ
необходимо взять виртуальный IP адрес узла 76 (ЯрТФОМС) SP TNO.
Программная реализация
Для взаимодействия с RabbitMQ необходимо реализовать два процесса:
1. Процесс публикации в очередь ТФ ОМС
2. Процесс приема сообщений из очереди УИВ
Каждое отправляемое и принимаемое сообщение должно иметь заголовок сообщения и его тело.
В заголовке сообщения передается информация следующего содержания:
1. protocol - тип протокола передаваемого в теле сообщения содержимого. (См. Порядок
обмена данными между учреждениями здравоохранения Ярославской области)
2. client_id – идентификатор УИВ отправляющего сообщения
3. package_id – идентификатор сообщения.
В теле сообщения в формате XML передается само сообщение согласно порядка обмена данными
между учреждениями здравоохранения Ярославской области.
Пример реализации
Все примеры написаны с использованием клиента под платформу .Net.
Создание подключения
private ConnectionFactory GetFactory()
{
ConnectionFactory factory = new ConnectionFactory();
factory.UserName = "tf_account";
factory.Password = "tf_account";
factory.VirtualHost = "/";
factory.Protocol = Protocols.DefaultProtocol;
factory.HostName = "11.0.0.99"; //Виртуальный IP узла 76 (ЯрТФОМС) SP TNO
factory.Port = AmqpTcpEndpoint.UseDefaultPort;
return factory;
}
Отправка сообщения
private void SendMessage( string messageBody )
{
// Имя обменника
string exchangeName = "TFOMS.Exchange";
// Имя очереди ТФ ОМС
string queueName = "TFOMS.Queue.7ADB0C1E-D488-4C2B-97FF-52D003FC47BD";
// Ключ маршрутизации. Всегда пустая строка
string routingKey = "";
using( IConnection conn = GetFactory().CreateConnection() )
{
using( IModel channel = conn.CreateModel() )
{
// Настройка обменника и очереди приемника
channel.ExchangeDelete( exchangeName );
channel.ExchangeDeclare( exchangeName, ExchangeType.Direct, true, false, null
);
channel.QueueDeclare( queueName, false, false, false, null );
channel.QueueBind( queueName, exchangeName, routingKey, null );
// Публикация сообщения
// Получение тела сообщения
byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes( messageBody );
// Построитель сообщения
var builder = new RabbitMQ.Client.Content.BytesMessageBuilder( channel );
// Настройка заголовка сообщения
builder.Headers["protocol"] = "A01";
builder.Headers["client_id"] = "E20AD2CF-2936-4329-9AF4-56B2FDAB0F3D";
builder.Headers["package_id"] = Guid.NewGuid().ToString();
// Тело сообщения
builder.WriteBytes( messageBodyBytes );
// Публикация сообщения
channel.BasicPublish( _exchangeName, _routingKey, ( IBasicProperties
)builder.GetContentHeader(), builder.GetContentBody() );
// Завершения сеанса (закрытие подключения)
channel.Close( 200, "Goodbye" );
}
}
}
Прием сообщения из очереди УИВ
Возможны два подхода к процессу получения.
1. Периодически опрашивать «свою» очередь
2. Через создание получателя
Рассмотрим пример на основе создания получателя работающего в отдельном потоке.
void _subscribeWorker_DoWork( object sender, DoWorkEventArgs eventArgs )
{
var worker = sender as BackgroundWorker;
if( worker == null )
{
return;
}
using( IConnection connection = GetFactory().CreateConnection() )
{
using( IModel channel = connection.CreateModel() )
{
QueueingBasicConsumer consumer = new QueueingBasicConsumer( channel );
//Подключаем "свою" очередь
String consumerTag = channel.BasicConsume(
"TFOMS.Queue.E20AD2CF-2936-4329-9AF4-56B2FDAB0F3D", false, consumer );
while( true )
{
if( worker.CancellationPending )
{
break;
}
try
{
RabbitMQ.Client.Events.BasicDeliverEventArgs e;
// Ожидаю получения сообщения
if( consumer.Queue.Dequeue( 1000, out e ) )
{
IBasicProperties props = e.BasicProperties;
byte[] body = e.Body;
// Обработка входящего сообщения
Dispatcher.BeginInvoke( new Action<string>(
SetSubscribedMessageText ),
System.Text.Encoding.UTF8.GetString( body
) );
channel.BasicAck( e.DeliveryTag, false );
}
}
catch( RabbitMQ.Client.Exceptions.OperationInterruptedException ex )
{
break;
}
}
channel.Close( 200, "Goodbye" );
}
}
}
Download