Надоело повторное COM-соединение? Не помещается COM-объект в хранилище? Есть решение!

Опубликовал Максим Жохов (ZhokhovM) в раздел Обмен - Перенос данных из 1C8 в 1C8

В этой статье описывается решение проблемы хранения COM-соединения, а также повторного соединения к базе каждый раз, как потребуется очередной обмен.

Итак, начнем с того, что в платформе 8.2 можно было сохранить соединение во временное хранилище. Как это делается:

л_COMОбъект=Новый COMОбъект("v82.Application");
л_АдресВХранилище=ПоместитьВоВременноеХранилище(л_COMОбъект, Новый УникальныйИдентификатор());

Ну и получать COM-объект из временного хранилища:

л_COMОбъект = ПолучитьИзВременногоХранилища(л_АдресВХранилище);

Но в платформе 8.3 возникает ошибка "Переданное значение не может быть помещено во временное хранилище".

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

 

л_COMОбъект = Новый COMОбъект("V83.Application");
л_Структура = Новый Структура("COMОбъект", л_COMОбъект);
л_АдресВХранилище = ПоместитьВоВременноеХранилище(л_Структура, Новый УникальныйИдентификатор());

Соответственно получаем:

л_COMОбъект = ПолучитьИзВременногоХранилища(л_АдресВХранилище).COMОбъект;

Важно: получать из хранилища только на сервере (если на сервере помещали), или аналогично на клиенте.

На этом статья заканчивается.

Здесь можно поддержать развитие публикации

Яндекс.Кошелек: 410012743280614

См. также

Лучшие комментарии

7. rulan87 semisal (rulan87) 25.02.2015 11:33
Есть другой способ: использовать модуль повторного использования, в котором получать функцией ком соединение. При первом обращении ком соединение кешируется
Ответили: (8) (10)
# Ответить
11. Сергѣй Батанов (baton_pk) 25.02.2015 13:21
Пилю out-of-process COM-класс для такого рода задач. Работает примерно так:
R = New ComObject("V8Pool.CacheConnector");
R.setCacheId("1");

A = R.connect("File=C:\Users\sbatanov\Documents\InfoBase12");
A.ОбщийМодуль1.SetCommonData("abababab");

R.setCacheId("2");

B = R.connect("File=C:\Users\sbatanov\Documents\InfoBase12");
B.ОбщийМодуль1.SetCommonData("dfdfdfdf");

A = Undefined;
B = Undefined;

R.setCacheId("1");
C = R.connect("File=C:\Users\sbatanov\Documents\InfoBase12");

Message(C.ОбщийМодуль1.GetCommonData()); // abababab
...Показать Скрыть


Мне нужно сохранять соединение между сеансами для работы веб-сервиса. По сути, разница с обычным КОМ-соединителем только в строке класса COM-объекта.
Ответили: (12) (17)
+ 4 [ tormozit; rtnm; BigB; ZhokhovM; ]
# Ответить
46. Степан Яранцев (infosoftvc) 09.03.2016 05:56
В какой-то момент времени на сервере перестал работать данный метод. Структура в хранилище сохраняется, но после чтения из хранилища данных нет ( л_Структура.COMОбъект = неопределено ).
Проблема решилась добавлением фиксированной структуры:
л_Структура = Новый ФиксированнаяСтруктура( Новый Структура("COMОбъект", л_COMОбъект));
Ответили: (47)
+ 2 [ tormozit; ZhokhovM; ]
# Ответить

Комментарии

1. Константин Юрин (kostyaomsk) 24.02.2015 07:07
Может стоит и попробовать прием, но опасно
COM-объект в хранилище
. А вдруг опять проблема с релизом платформы?
# Ответить
2. Андрей Карпов (karpik666) 24.02.2015 09:13
И такой способ реально работает?
Ответили: (3)
# Ответить
3. Максим Жохов (ZhokhovM) 24.02.2015 09:17
(2) karpik666, да.
# Ответить
4. Сергей Старых (tormozit) 24.02.2015 09:51
В примере для 8.3 забыл про второй параметр метода ПоместитьВоВременноеХранилище
Ответили: (5)
# Ответить
5. Максим Жохов (ZhokhovM) 24.02.2015 09:53
(4) tormozit, точно. Спасибо.
# Ответить
6. Андрей Калякин (kalyaka) 24.02.2015 09:56
В 8.3 может и не сработать, см. "Особенности временного хранилища" в публикации http://infostart.ru/public/198766/
Ответили: (32)
+ 1 [ BigB; ]
# Ответить
7. rulan87 semisal (rulan87) 25.02.2015 11:33
Есть другой способ: использовать модуль повторного использования, в котором получать функцией ком соединение. При первом обращении ком соединение кешируется
Ответили: (8) (10)
# Ответить
8. Сергей Старых (tormozit) 25.02.2015 12:48
(7) Через 20 мин однако это значение из кэша удаляется.
Ответили: (9)
# Ответить
9. Максим Жохов (ZhokhovM) 25.02.2015 12:50
(8) tormozit, ага, конечно.
# Ответить
10. Максим Жохов (ZhokhovM) 25.02.2015 12:55
(7) rulan87, да, на время сеанса либо COM+.
# Ответить
11. Сергѣй Батанов (baton_pk) 25.02.2015 13:21
Пилю out-of-process COM-класс для такого рода задач. Работает примерно так:
R = New ComObject("V8Pool.CacheConnector");
R.setCacheId("1");

A = R.connect("File=C:\Users\sbatanov\Documents\InfoBase12");
A.ОбщийМодуль1.SetCommonData("abababab");

R.setCacheId("2");

B = R.connect("File=C:\Users\sbatanov\Documents\InfoBase12");
B.ОбщийМодуль1.SetCommonData("dfdfdfdf");

A = Undefined;
B = Undefined;

R.setCacheId("1");
C = R.connect("File=C:\Users\sbatanov\Documents\InfoBase12");

Message(C.ОбщийМодуль1.GetCommonData()); // abababab
...Показать Скрыть


Мне нужно сохранять соединение между сеансами для работы веб-сервиса. По сути, разница с обычным КОМ-соединителем только в строке класса COM-объекта.
Ответили: (12) (17)
+ 4 [ tormozit; rtnm; BigB; ZhokhovM; ]
# Ответить
12. Сергей Старых (tormozit) 25.02.2015 15:42
(11) baton_pk, когда планируешь допилить? Что будет если два сеанса одновременно запросят один и тот же CacheId? В какой момент уничтожается объект или он работает резидентно через COM+?
Ответили: (13) (14)
# Ответить
13. Сергѣй Батанов (baton_pk) 25.02.2015 16:27
(12) tormozit,

когда планируешь допилить?

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


Что будет если два сеанса одновременно запросят один и тот же CacheId?

Они получат один и тот же COM-объект. Потому у меня в качестве id используется имя пользователя, а одновременная работа двух пользователей с одним именем у меня отсекается на уровне логики приложения.


В какой момент уничтожается объект или он работает резидентно через COM+?

С этим сейчас у меня пока творческий ступор: как сделать лучше. Это COM+ (насколько я знаком с терминологией), то есть EXE-сервер. Сейчас он выключается по истечении некоторого таймаута после отключения последнего сеанса. То есть как-то так:

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

как только все-все-все отсоединятся, запускается таймер-убийца (для отладки у меня 10 секунд стоит, но в боях я буду минут 10 выставлять). Если по истечении времени не было новых соединений, то EXE-сервер закрывается и закрывает все 1С-соединения. Следующее соединение уже запустит новый чистый EXE-сервер.

Не запутаться бы, где какое соединение :-)
Ответили: (15)
# Ответить
14. Сергѣй Батанов (baton_pk) 25.02.2015 16:30
(12) tormozit,
Что будет если два сеанса одновременно запросят один и тот же CacheId?

Тут надо ещё один момент уточнить: сопоставление идёт не CacheId => ComObject, а {CacheId, ConnectionString} => ComObject.

То есть в одном кэше два подключения к разным базам (или под разным пользователем и т.д.) - это разные объекты, разумеется.
# Ответить
15. Сергей Старых (tormozit) 25.02.2015 17:06
(13) baton_pk, про COM+ описал правильно. Твоя реализация судя по описанию не позволяет конкурентно использовать пул внешних соединений. Про ограничение количества сеансов на одного пользователя я так понял, что в случае обслуживания операции веб-сервиса сразу от нескольких клиентов только один из них получит ответ, а остальные отказ.
Ответили: (16)
# Ответить
16. Сергѣй Батанов (baton_pk) 25.02.2015 17:46
(15) tormozit, Нет, у меня разные клиенты под разными пользователями входят. Соответственно, у каждого свой кэш получается.
Если тебе нужно, чтобы внутри одного сеанса хранился объект, то в качестве идентификатора кэша можно использовать имя пользователя и номер сеанса. А если всё-таки между сеансами перебрасывать, то тут либо пользователей разносить, либо какой-то механизм сессий вводить, когда ты клиенту передаёшь идентификатор при первом соединении и клиент с этим идентификатором дальше с тобой общается (типа сессий в PHP). Я пока в эту сторону думаю.
# Ответить
17. rtnm rtnm (rtnm) 26.02.2015 08:33
(11) baton_pk, а замерял на сколько падает производительность при использовании V8Pool.CacheConnector? В моей реализации подобного пула (больше похожего на то что описывал tormozit - конкурентное получение соединения из пула с фиксированным размером) производительность упала в 10-20 раз. Замерял время на сортировке, т.е. на коде который совершает много мелких вызовов. Даже осознавая присутствие маршалинга, я был сильно разочарован и "заморозил" разработку.
Ответили: (18)
# Ответить
18. Сергѣй Батанов (baton_pk) 26.02.2015 08:41
(17) rtnm, нет, замерами не занимался. мне просто даже в голову не пришло, что поиск соединения в пуле может быть в разы медленнее, чем создание нового соединения с Комплексной Автоматизацией.
Ответили: (19)
# Ответить
19. rtnm rtnm (rtnm) 26.02.2015 09:24
(18) baton_pk, причем тут поиск соединения? Речь про затраты на маршалинг.
Ответили: (20)
# Ответить
20. Сергѣй Батанов (baton_pk) 26.02.2015 09:42
(19) rtnm, тогда я не понимаю, что с чем надо сравнивать?
что через CacheConnector, что через родной ComConnector работа в итоге идёт через один и тот же класс внешнего соединения? Маршаллинг в любом случае присутствует.
Ответили: (21)
# Ответить
21. rtnm rtnm (rtnm) 26.02.2015 10:16
(20) baton_pk, я, например, сравнивал скорость работы алгоритма сортировки (не помню какого точно), генерировал массив с воспроизводимыми псевдослучайными значениями, и запускал сортировку:
1. в обычной среде выполнения 1С
2. с использованием V8x.ComConnector (без учета времени подключения)
3. с использованием своей компоненты, аналог вашей V8Pool.CacheConnector (без учета времени подключения)

Так вот 3 получался медленнее 1 примерно в 10-20 раз. 2 тоже был медленнее 1, но не так сильно.
Естественно для 2 и 3 речь идет о том, что сам алгоритм сортировки располагался в базе которая подключается, а не к которой подключаются.

Маршалинг в 2 и 3 присутствует, но он разный, в случае 3 он будет межпроцессным.

Было бы интересно увидеть ваши замеры.
Ответили: (22)
+ 1 [ baton_pk; ]
# Ответить
22. Сергѣй Батанов (baton_pk) 26.02.2015 10:53
(21) rtnm, померял.
Сделал две сортировки: одну "в лоб", одну "правильно".
В лоб разница существенная: 10 секунд против 88.
Правильно - это с сокращением количества "клиент-серверных" вызовов. Там разница 2 мс против 4 мс.

Не вижу поводов отчаиваться, при правильно построенной логике клиент-серверного взаимодействия разница в скорости будет мала.
Грубо говоря, вместо
Для Каждого КомЭлемент Из КомСписок Цикл
	КомБаза.КомОбработать(КоэмЭлемент);
КонецЦикла;
...Показать Скрыть

Надо делать:
КомБаза.КомОбработатьСразуСписок(КомСписок);


PS. Но разницу в маршаллинге внутри процесса и между процессами зарубил себе на носу в любом случае. Спасибо.
Ответили: (23)

Прикрепленные файлы:

Обработка.Сортировка.Команда.КомандаВыполнитьСортировку.МодульКоманды.txt
Обработка.Сортировка.Команда.КомандаВыполнитьСортировкуПравильно.МодульКоманды.txt
# Ответить
23. rtnm rtnm (rtnm) 26.02.2015 11:15
(22) baton_pk, спасибо за замеры, появилась мысль "разморозить" разработку, найти бы только время :)

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

Например, есть типовая конфигурация на полной поддержке. Необходимо сделать для нее веб-сервис(http-сервис) со следующими ограничениями:
1. Не снимать полную поддержку с типовой конфигурации
2. Реализовать логику работы веб-сервиса(http-сервис) средствами 1С, чтобы любой разработчик 1С мог в ней разобраться (без подключения других инструментов, например, ASP.NET)
3. Получить в итоге адекватное время ответа от веб-сервиса(http-сервиса).

Кстати, еще одной причиной "заморозки" моей разработки являлась анонсированная в 8.3.6 возможность расширений, в которой я думал будет возможность, например, подключать веб-сервисы и http-сервисы, но пока этого не случилось.
Ответили: (24)
# Ответить
24. Сергѣй Батанов (baton_pk) 26.02.2015 11:22
(23) rtnm,
снимать типовую конфигурацию с полной поддержки.

А если попробовать через внешнее соединение подключать внешнюю обработку и всю логику запихивать туда?
Ответили: (25)
# Ответить
25. rtnm rtnm (rtnm) 26.02.2015 11:37
(24) baton_pk, этот вариант нужно всегда иметь на заметке. Конкретно в моем случае, я использую pool com-конектора, и обработку надо будет постоянно загружать заново, потому что она будет выгружаться при завершении соединения и помещении его в pool. В общем тут надо подумать :)
# Ответить
26. Яков Коган (Yashazz) 26.02.2015 13:16
Мне одному кажется, что за попытку передать com-соединение на сервер надо люто минусовать этот бред?
И что эта, простигосспади, "статья" противоречит рекомендациям 1С по разработке?
# Ответить
27. Максим Жохов (ZhokhovM) 26.02.2015 13:44
Мне одному кажется, что за попытку передать com-соединение на сервер надо люто минусовать этот бред?

Попробуйте создать реквизит обработки произвольного типа и хранить com-объект в нем.
Ответили: (28)
# Ответить
28. Яков Коган (Yashazz) 26.02.2015 13:46
(27) ZhokhovM, это не ответ. Сама попытка передачи COM-соединения с клиента на сервер - это грубейшая ошибка. В 8.2 защита ещё не была доведена до ума, поэтому позволяла такие хамские вольности, в 8.3 это, к счастью, пресекли.
Ответили: (29)
# Ответить
29. Максим Жохов (ZhokhovM) 26.02.2015 14:00
(28) Yashazz, цитирую из статьи:
Важно: получать из хранилища только на сервере (если на сервере помещали), или аналогично на клиенте.
# Ответить
30. Яков Коган (Yashazz) 26.02.2015 14:09
А, то есть речь о работе клиент-клиент или сервер-сервер? Тогда да, согласен, нормально.
# Ответить
31. Виктор Назаров (androgin) 03.03.2015 02:44
ай ай, как не хорошо тырить чужие идеи ))))
http://forum.infostart.ru/forum86/topic118827/message1282941/#message1282941
Ответили: (33)
# Ответить
32. Виктор Назаров (androgin) 03.03.2015 02:45
(6) kalyaka, в 8.3 все прекрасно работает!
Ответили: (40)
# Ответить
33. Максим Жохов (ZhokhovM) 03.03.2015 09:14
(31) androgin, псс-с. Всего-то помаленьку.
Ответили: (34)
# Ответить
34. Виктор Назаров (androgin) 03.03.2015 21:54
(33) ZhokhovM, lf да ты стырил ВСЁ, только префиксы добавил.
Только мой вариант более живучий, чем твой)))
Догадайся почему))
Ответили: (35)
# Ответить
35. Максим Жохов (ZhokhovM) 04.03.2015 10:07
(34) androgin, ну я сперва начал искать ответы на разных сайтах, решил сделать статью и показать другу, как это работает в 8.3. Могу привести ссылки:
http://forum.infostart.ru/forum86/topic118827/
http://forum.infostart.ru/forum26/topic103575/
http://forum-mista.pro/topic.php?id=714692/
были еще ссылки...

Только мой вариант более живучий, чем твой)))
Догадайся почему))

м.б. то что на клиенте у меня не работает или нет глобальной переменной?
Ответили: (36)
# Ответить
36. Виктор Назаров (androgin) 09.03.2015 19:45
(35) ZhokhovM, Если бы ты сам писал код, то имена переменных, вплоть до расстановки знаков, не были бы идентичны
Ответили: (37)
# Ответить
37. Андрей Карпов (karpik666) 10.03.2015 06:15
(36) androgin, Я просто оставлю это здесь http://infostart.ru/public/294285/
Ответили: (38)
# Ответить
38. Максим Жохов (ZhokhovM) 10.03.2015 10:57
(37) karpik666, хорош спамить.
Ответили: (39)
# Ответить
39. Андрей Карпов (karpik666) 10.03.2015 17:48
(38) ZhokhovM, вообще-то это не спам, просто дополнение к вашей беседе, кто у кого и сколько скопировал=)
Ответили: (41)
# Ответить
40. Андрей Калякин (kalyaka) 13.03.2015 16:18
(32) androgin, а если кластер состоит из нескольких рабочих серверов и произойдет переподключение с одного рабочего сервер на другой?
# Ответить
41. Виктор Назаров (androgin) 20.03.2015 01:39
(39) karpik666, Если ты не понял сути, то зачем встревать со своей статьей?))
# Ответить
42. Сергей Галюк (dj_serega) 27.04.2015 09:36
Спасибо за статью. Отработало как часы.
Ответили: (43)
# Ответить
43. Максим Жохов (ZhokhovM) 27.04.2015 09:47
(42) dj_serega, пожалуйста.
# Ответить
44. 09.09.2015 11:39
Добрый день.

А как быть с временем соединения... спустя минуту COM автоматически сбрасываться(
(Используются серверные базы)

Можно как-то настроить?
# Ответить
45. Сергей Старых (tormozit) 17.01.2016 16:08
Есть еще такой метод v82Server.dll - Технология Microsoft COM+ для доступа к 1C82, но посложнее в настройке конечно и нет готовых бинарников/исходников для 8.2+
# Ответить
46. Степан Яранцев (infosoftvc) 09.03.2016 05:56
В какой-то момент времени на сервере перестал работать данный метод. Структура в хранилище сохраняется, но после чтения из хранилища данных нет ( л_Структура.COMОбъект = неопределено ).
Проблема решилась добавлением фиксированной структуры:
л_Структура = Новый ФиксированнаяСтруктура( Новый Структура("COMОбъект", л_COMОбъект));
Ответили: (47)
+ 2 [ tormozit; ZhokhovM; ]
# Ответить
47. Максим Сердюков (Caliban) 15.04.2016 08:46
(46) infosoftvc, у меня сегодня внезапно тоже перестал сохраняться COM-объект в структуре. До этого больше года работало как часы. Вариант с фиксированной структурой не помог. Кто нибудь еще сталкивался с таким?
Ответили: (48)
# Ответить
48. Андрей Калякин (kalyaka) 28.04.2016 11:50
(47) Caliban, не все com объекты поддерживают сериализацию. Еще, возможно, сама 1С не сериализует com, а использует ссылку на существующий объект и если происходит переподключение с одного рабочего процесса на другой, то не факт, что будет сохранен com объект.
# Ответить
49. Сергей Смирнов (Serginio) 28.04.2016 12:36
Я бы на нет сделал статическое свойство (синглетон) Dictioanary<string,object> который бы по ProgID отдавал нужную ссылку и создавал её если еще не создавалась. Загруженные библиотеки не выгружаются из процесса. И этот синглетон будет жить пока рабочий процесс не перегрузится.
# Ответить
Внимание! За постинг в данном форуме $m не начисляются.
Внимание! Для написания сообщения необходимо авторизоваться
Текст сообщения*
Прикрепить файл