Организация обмена с помощью шины сообщений MSMQ




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

55 Comments

  1. mini_root

    блин, код уехал…

    Reply
  2. mini_root

    а как кошерно вставить 1с’вский код в редакторе статей?

    Reply
  3. mini_root

    Мдааа… вот скажите, зачем было разукрашку выкладывать только для зарегистрированных и тремя разными файлами. Ну шо, ждем 00 часов чтобы скачать xml’ник…

    Reply
  4. mini_root

    ступил… ну вот, кажись все, жду комментариев и конструктивной критики

    Reply
  5. CheBurator

    интересно, а можно с помощью этой шины сообщенйи организовать обмен между 2-я сеансами 1Ски?

    Reply
  6. CheBurator

    Качество мультика — отвратное

    Reply
  7. mini_root

    (5) Элементарно, если каждому сеансу будет присвоена своя очередь, например, можно сопоставить справочник сотрудников пользователям 1С и дописать в справочник реквизитом очередь, которую надо будет опрашивать. Таким образом каждый экземпляр/сеанс будет знать откуда ему получать сообщения, плюс у него будет «адресная книга» с очередями всех остальных экземпляров. Экземпляры/сеансы должны в данном случае отличаться друг от друга по пользователям.

    (6) Ютуб, шо ты хочешь, там еще кнопочка HD есть — чуть получше будет.

    Reply
  8. mini_root

    (7) Собственно, чтобы организовать обмен между двумя совместимыми по данным системами тебе нужно знать только откуда читать и куда писать. Ну и учесть те или иные особенности систем (типа удаления регистрации и игры с номерками в 1С).

    Reply
  9. mini_root

    (8) Обмен сообщениями может идти даже в рамках одного процесса, есть у ActiveMQ такой режим — транспорт внутри JVM. В приложении с большим количеством потоков позволяет обменивать данными не через общие переменные, и, как следует, избежать синхронизации. Аналогично сделано в эрланге, там это вообще основной способ взаимодействия.

    Reply
  10. mini_root

    (9) Более того, в рамках многопоточного процесса(ов) можно даже использовать внешнюю шину, сохраняющую сообщения в некоем постоянном хранилище — это позволит получить восстановление состояние процесса(ов) после сбоя. По крайней мере в границах транзакций шины сообщений, если кто-то успел что-то положить и сказать commit — его это уже больше не волнует, если кто-то не успел получить что-то и сказать commit — он получит это еще раз.

    Reply
  11. steban

    чтобы собрать проект в VS2008 пришлось добавить NUnit в GAC

    Reply
  12. steban

    Хорошее начинание. Можно сделать из этого конфетку.

    и да, EIP рулит 🙂

    Reply
  13. steban

    было бы неплохо не пинать очередь на предмет наличия сообщений, а привязать событие прихода сообщения к какому-нибудь обработчику в 1С.

    Reply
  14. mini_root

    а обработчик как вызывать из ВК? прокинуть во внешнюю компоненту экземпляр обработки и дергать у нее методы? Или оформить все в виде псевдо активикса? какие еще возможны варианты?

    P.S. Или поднять опрос очереди в виде отдельного сервиса, а из него при поступлении сообщений поднимать V8.Application и вызывать обработчик, передавая ему в качестве аргумента адаптер, чтобы можно было полностью контролировать транзакцию.

    Reply
  15. mini_root

    (12) Можно и конфетку, самое главное найти этому применение…

    В планах на ближайшую неделю-другую устроить краш тест — создать по 200 тысяч элементов в номенклатуре, добавить какой-нибудь реквизит и менять его в центре и на магазине, гоня все это дело туда сюда. Ну и переписать обработку так, чтобы все билось на несколько сообщений. Заодно сделать сообщения об ошибках в виде структурированного xml.

    Reply
  16. mini_root

    (11) Там огрызок от юнит теста, которым я отлавливал глюк в agsXMPP.

    Reply
  17. steban

    (14) угу, прокинуть экземпляр обработки и дергать методы.

    или вызывать методы глобального контекста.

    Reply
  18. mini_root

    (17) А как передать глобальный контекст текущего сеанса в ВК?

    Reply
  19. steban

    (18) ВК может запросить свойство AppDispatch у указателя, полученного в Init.

    Это и будет «глобальный контекст».

    Только это должен быть объект ВК, а не просто COM-объект.

    Reply
  20. steban

    +(19) немного ссылочек:

    http://www.rsdn.ru/article/dotnet/cs1c.xml

    Reply
  21. mini_root

    (20) спасибо, посмотрю

    Reply
  22. Душелов

    А если ВК, значит никакого серверного варианта.

    Reply
  23. mini_root

    А если COM? GetCOMObject на сервере доступен?

    Reply
  24. Душелов

    (23) Ком работает, так, но не передается контекст 1С

    Reply
  25. mini_root

    тогда возможно стоит отказаться от идеи обработчика и вызывать HasMessages в регламентом задании

    Reply
  26. Душелов

    А зачем нужен контекст 1С? Вообще, стоит подобную систему организовать в качестве службы, которая при получение входящих сообщений подключалась бы к 1С и производила необходимые действия.

    Reply
  27. mini_root

    (26) как вариант

    А чем принципиально плохо опрашивать очередь из 1С? Например, из регламентного задания.

    Reply
  28. Душелов

    (27) А то, что ты будешь опрашивать каждый заданный интервал времени, когда можно инициировать обработку данных только после получения сообщения.

    Reply
  29. mini_root

    (28) И? Опрашивать в регламентном задании раз в 5-10 минут — интервал зависит от интенсивности и размера сообщений, можно хоть раз в час.

    Reply
  30. CheBurator

    (29) не нравится! почувствуй разницу в двух задачах: выполнить действие при приходе сообщения извне и проверять, а не случилось ли сообщение и если да — тогда что-то сделать… Допустим у меня есть в сутки 5 критичных сообщений, которые д.б. обработаны не позже чем через 5 сек после их прихода. и мне что — каждые 5 сек дергаться-проверять? вместо того, чтобы по приходу сообщения тут же выполнить то, что надо…

    Reply
  31. mini_root

    (30) можно узнать, что за задача требует такой реакции? вряд ли это обмен

    Reply
  32. CheBurator

    обмен как таковой меня не интересует пока.

    если сможете «нарисовать» красивую схему когда разные сеансы 1Ски, работающие в одной базе, обмениваются инфой/сообщениями. полученное сообщение может породить длинную цепочку действий. Я НЕ ХОЧУ ПРОВЕРЯТЬ ПРИШЛО ЛИ СООБЩЕНИЕ, я хочу после прихода сообщения получить «сигнал», и по наличию этого сигнала что-то сделать.

    Reply
  33. mini_root

    (32) Как уже выше предлагалось оформить все в в виде ВК, тем более, что судя по всему Вас вполне устроит работа в на клиентской стороне.

    В метод Init ВК приезжает контекст одинэски а в SetParameter скармливается имя процедуры в глобальнике. При получении сообщения эта процедура дергается и ей скармливается аргументом сам адаптер, чтобы внутри процедуры можно было иметь полный контроль на транзакцией, ну а там в цикле точно также получаются все сообщения. В следующей версии можно попробовать реализовать.

    Reply
  34. Аверков

    Скиншот 1

    Кеды «Престарелый гопник» экстрим эдишн

    Охренеть — дайте две! 🙂

    Reply
  35. alex_4x

    А зачем такой геморой ? Уж если применять шину данных, то пользоваться серьзным, промышленным решением, типа BizTalk.

    Reply
  36. mini_root

    (36) Можно и так, но я с ним не сталкивался — это первое. Особого геморроя я тут не вижу — это второе, дешево и вполне способно заменить файловый обмен, особенно с учетом того, что сообщения в файлы все равно сохраняются и повторная отправка делается на счет раз. Ну а если в середину вставить XSL трансформатор, то можно и с другими системами меняться.

    Ну и наконец, с таким же интерфейсом можно сделать адаптеры к другим системам обмена сообщениями, например, к ActiveMQ — а это уже быдложабка 2 EE (я специально сделал один интерфейс для MSMQ и для XMPP, чтобы это продемонстрировать). Интеграция с BizTalk’ом вряд ли будет чем-то отличаться от вариантов приведенных в статье и в обсуждении. И опять же, не бизтолком единым, есть и другие решения — COM, XML сериализация и планы обмена дают большой простор для фантазии, например, я знаю как можно интегрировать эску с практически любым ESB (пробовал на OpenESB).

    Reply
  37. steban

    >я знаю как можно интегрировать эску с практически любым ESB (пробовал на OpenESB)

    с этого момента, пожалуйста, поподробней

    Reply
  38. mini_root

    (37) будет время, постараюсь еще одну статейку накатать

    Reply
  39. hotey

    А кто-нибудь пробовал в сети этот пример запустить? Проходят сообщения?

    Reply
  40. lustin

    (39)

    Я пробовал, все работает 😉

    Reply
  41. hotey

    (40) А у меня всё получилось только после целого ряда дополнительных телодвижений. Большая часть была произведена возможно по своей неопытности, но пришлось даже свойства сборки менять и dll перекомпилировать. Я правда пытался связь между XP и 2003 Server наладить…

    Reply
  42. mini_root

    (41) Интересно, а какие компоненты MSMQ дополнительно ставили? На висту хоум басик многих вещей не поставишь.

    Reply
  43. hotey

    (42) Локально на одной машине заработало так как и было. То есть на XP пришлось только прорегистрировать DLL с помощью regasm.exe.

    А вот на Win2k3 Server пришлось в AssemblyInfo.cs прописать:

    using System.Security;

    [assembly: AllowPartiallyTrustedCallers()]

    И перекомпилить — только после этого пошло…

    Что касается непосредственно компонентов MSMQ, то в итоге стоят почти все доступные. 🙂

    Сейчас только осталось разобраться с роутингом и прочими наворотами, чтобы сообщения проходили между хостами, которые не пересекаются во времени.

    Reply
  44. mini_root

    (43) Спасибо, если будет возможность и желание — поделитесь опытом, например, в виде статьи.

    P.S. А я постараюсь через недельку подогнать еще одну, на этот раз на тему интеграции 1С с шиной веб-сервисов OpenESB.

    Reply
  45. hotey

    (44) Да собственно на статью материала маловато. Все полезные выводы уместились в предыдущий комментарий.

    Reply
  46. mini_root

    А вот взгляд на интеграцию с другой точки: http://infostart.ru/blogs/1236/

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

    Reply
  47. igor-bts

    Вопрос, а как эта система будет работать в распределенной (через интернет) сети?

    Reply
  48. mini_root

    Ну, во-первых, у MSMQ есть множество разных компонентов (с TCP транспортом, с HTTP и пр.).

    Во-вторых, в строке соединения с очередью можно указывать транспорт и имя узла, если не ошибаюсь, что-то такое:

    DIRECT=TCP:IPAddressQueueName;

    Это ж у меня все локально аля «.Private$….»

    В-третьих, вон там выше есть товарищ с ником hotey, он наладил обмен между разными узлами внутри локалки.

    P.S. Кроме того там есть еще такая вещь как каналы http://www.codeproject.com/KB/IP/msmqchannel.aspx

    Reply
  49. mini_root

    http://msdn.microsoft.com/en-us/library/ms700996(VS.85).aspx

    >Direct format names are used to reference public or private queues without accessing the directory service. Direct format names are used when performing the following operations:

    * Sending messages directly to a computer.

    * Sending messages to computers over the Internet.

    * Sending messages across forest boundaries.

    * Sending messages to any queue while operating in domain, workgroup, or offline mode.

    * Reading messages while operating in domain, workgroup, or offline mode.

    там же:

    > DIRECT=TCP:157.18.3.1MyQueue

    Reply
  50. mini_root

    Но:

    >Security Limitations

    >Opening a remote queue for sending messages with a direct format name signals Message Queuing not to query the directory service when it opens the queue. This enables Message Queuing to send messages in workgroup and offline mode and to transmit messages across forest boundaries, but it eliminates the possibility of using some of the security functionality provided by Message Queuing for access control, authentication, and encryption. When security services performed by Message Queuing are unavailable, it is the responsibility of your application to implement the missing functionality.

    Reply
  51. mini_root

    Хотя если есть VPN, то наверное не страшно.

    Вот вроде бы вариант с использованием HTTPS: http://technet.microsoft.com/en-us/library/cc736680(WS.10).aspx

    Reply
  52. mini_root

    В случае с HTTPS все сводится к разрешению подключения только доверенных клиентов и раздаче этим клиентам сертификатов. Сертификат есть, подключишься, сертификата нету:

    IIS 5.0: HTTP 403.16 Forbidden: Client Certificate Untrusted or Invalid.

    или что-то подобное

    Ну и у сервера свой сертификат должен быть.

    Reply
  53. matytsin_new

    Поправьте меня, если я ошибаюсь.

    1) MSMQ позволяет сохранять сообщения для отправки в очереди.

    2) а что будет, если адресат, которому эта очередь предназначена не будет регулярно получать сообщения?

    Т.е. ситуация: Имеем нерадивого подписчика обмена, который не хочет, не умеет, забывает делать обмен, в мерцающем режиме появляется в Интернете и как результат не забирает сообщения, которые ему предназначены.

    Далее. Характер данных, передаваемых в обмене имеет существенно древовидную структуру, такую, что загрузка последующих сообщений без загрузки предыдущих — просто разрушит целостность дерева у клиента. Т.о. мы не можем очистить его очередь или оптимизировать его сообщения так, чтобы их количество и объем уменьшились.

    Тогда мы получаем потенциальную опасность безграничного разрастания очереди для получателя обмена.

    Если количество получателей будет измеряться многими сотнями, а то и тысячами, то данная схема должна предусматривать возможность защиты от пожобных ситуаций, иначе мы просто впустую сожрем место на сервере MSMQ

    Reply
  54. mini_root
    Reply
  55. mini_root

    В качестве иллюстрации того, что при желании схему можно закрутить как угодно: при некоторой степени извращенности можно собрать кластер для бедных, в виде фоновой службы запущенной на офисных компах, которая через специальные очереди (или еще как) выгребает код скрипта или готовую библиотеку с точкой входа, а потом обрабатывает сообщения-запросы в соответствии с загруженной логикой, потихоньку отъедая избыточную вычислительную мощность у секретарши Маши и кадровички Любы.

    Пнул новый скрипт/библиотеку — изменил логику обработки. Маша выключила компьютер? Не страшно, ведь осталась Люба! Правда остается еще вопрос с источником данных, в него тоже можно упереться (производительность/блокировки).

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *