Передача большого количества объектов через Web-сервисы

Обмен - Интеграция с WEB

Один из вариантов передачи большого количества объектов при использовании Web-сервисов.

Дисклеймер

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

Вместо введения 

Собственно, что мы имеем - имеем две конфигурации, одна написанная с нуля для работы кассиров в магазинах, так называемый FrontOffice, вторая Управление торговлей, редакция 11.2 (11.2.3.108). В обе конфигурации встроена БСП версии 2.3.2.50.  Между конфигурациями существует обмен данными через Web-сервисы. Сам обмен и транспорт обмена полностью типовой, добавлен только свой план обмена. Обмен между базами происходит раз в 5 минут и в среднем очень маленький, в пределах 100 - 150 объектов за одну итерацию. Ввиду того что обмен работает через Web-сервис а магазины (FrontOffice) географически находятся в разных местах мы имеем несколько ограничений. Первое ограничение связано с тем что с разными магазинами (FrontOffice) разные каналы связи, которые соответственно имеют разную пропускную способность (от 2 Мбит до 50 Мбит), что в свою очередь накладывает серьезные ограничения на передаваемый объем данных. Второе ограничения связано с передачей данных на стороне веб сервера. Как пишут в статьях и на форумах максимальный размер пакета, который стабильно может передаваться через веба сервер варьируется от 16 Мб до 30 Мб (при настройках по умолчанию в зависимости от Web-сервера).  По факту, ради эксперимента, я передавал файл через Web-сервис размером примерно 130 Мб в локальной сети, и он проходил, без каких-либо доработок, но не понятно, как это сказывалось на работоспособности веб сервера (так как не рекомендуется передавать данные больше нескольких Мб) и как бы это все происходило при пропускной способности канала 2 Мбита.

О проблеме 

Суть проблемы заключается в том, что в определённый момент времени нужно передать порядка> 60000 объектов + примерно 40000 объектов должны были выгрузиться по ссылкам. При попытке выгрузить такое количество данных на магазин с пропускной способностью канала в 50 Мбит происходило следующее. План обмена на стороне инициатора обмена показывал, что все данные успешно выгружены, не сжатый файл выгрузки при этом "весил" примерно 800 Мб в сжатом виде примерно 13 Мб. А на принимающей стороне отображалось информация о том, что ничего не происходит и весь журнал регистрации заполнялся ошибками, т.к. обмен пытался каждые 5 минут запуститься заново, но не запускался из-за ошибки, что уже идет обмен данными. Так могло продолжаться пол дня и сутки и ничего в итоге не загружалось, обмен просто подвисал. По идее, при передачи данных через web-сервис (если верить исходному коду и описанию) происходит разбивка выгружаемых данные на файлы примерно по 1 Мб их передача, а затем склеивание и загрузка. Происходит это в общем модуле ОбменДаннымиСервер:

// Функция передает указанный файл в сервис передачи файлов.
//
// Параметры:
//  ИмяФайла                 - Строка - путь к передаваемому файлу.
//  ПараметрыДоступаКСервису - Структура: АдресСервиса, ИмяПользователя, ПарольПользователя. 
//  РазмерЧасти              - Число - размер части в килобайтах. Если значение равно 0,
//                             то разбивка на части не производится.
// Возвращаемое значение:
//  УникальныйИдентификатор  - идентификатор файла в сервисе передачи файлов.
//
Функция ПоместитьФайлВХранилищеВСервисе(Знач ИмяФайла, Знач УзелИнформационнойБазы, Знач РазмерЧасти = 1024, Знач ПараметрыАутентификации = Неопределено)
	
	// Возвращаемое значение функции.
	ИдентификаторФайла = Неопределено;
	
	Прокси = ПолучитьWSПроксиДляУзлаИнформационнойБазы(УзелИнформационнойБазы,, ПараметрыАутентификации);
	
	ОбменВыполняетсяВОднойСети = ОбменДаннымиПовтИсп.ОбменВыполняетсяВОднойЛокальнойСети(УзелИнформационнойБазы, ПараметрыАутентификации);
	
	Если ОбменВыполняетсяВОднойСети Тогда
		
		ИмяФайлаВХранилище = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременногоХранилищаФайлов(), УникальноеИмяФайлаСообщенияОбмена());
		
		ПереместитьФайл(ИмяФайла, ИмяФайлаВХранилище);
		
		Прокси.PutFileIntoStorage(ИмяФайлаВХранилище, ИдентификаторФайла);
		
	Иначе
		
		КаталогФайлов = ПолучитьИмяВременногоФайла();
		СоздатьКаталог(КаталогФайлов);
		
		// Архивирование файла
		ИмяНеразделенногоФайла = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогФайлов, "data.zip");
		Архиватор = Новый ЗаписьZipФайла(ИмяНеразделенногоФайла,,,, УровеньСжатияZIP.Максимальный);
		Архиватор.Добавить(ИмяФайла);
		Архиватор.Записать();
		
		// Разделение файла на части
		ИдентификаторСессии = Новый УникальныйИдентификатор;
		
		КоличествоЧастей = 1;
		Если ЗначениеЗаполнено(РазмерЧасти) Тогда
			ИменаФайлов = РазделитьФайл(ИмяНеразделенногоФайла, РазмерЧасти * 1024);
			КоличествоЧастей = ИменаФайлов.Количество();
			Для НомерЧасти = 1 По КоличествоЧастей Цикл
				ИмяФайлаЧасти = ИменаФайлов[НомерЧасти - 1];
				ДанныеФайла = Новый ДвоичныеДанные(ИмяФайлаЧасти);
				Прокси.PutFilePart(ИдентификаторСессии, НомерЧасти, ДанныеФайла);
			КонецЦикла;
		Иначе
			ДанныеФайла = Новый ДвоичныеДанные(ИмяНеразделенногоФайла);
			Прокси.PutFilePart(ИдентификаторСессии, 1, ДанныеФайла);
		КонецЕсли;
		
		Попытка
			УдалитьФайлы(КаталогФайлов);
		Исключение
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииУдалениеВременногоФайла(),
				УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		
		Прокси.SaveFileFromParts(ИдентификаторСессии, КоличествоЧастей, ИдентификаторФайла);
		
	КонецЕсли;
	
	Возврат ИдентификаторФайла;
КонецФункции

Да и действительно файл разбивается на части, в случае если он больше 1 Мб и передается, но в нашем случае данные метод не помогает, обмен все равно зависает, где то при попытке все эти данные передать и загрузить. Тогда в общем то и родилась идея передавать данные частями, а точнее выгружать определённое количество объектов за одну итерацию обмена данными. К примеру, если зарегистрировано 10000 изменений по справочникам мы их выгружаем по 1000 за одну итерацию обмена, пока не выгрузим все 10000 объектов. Тем самым мы уменьшаем нагрузку на канал, уменьшаем время выгрузки и загрузки за одну итерацию и в общем если канал связи совсем слабый, то гарантированно передаем необходимое количество данных за раз. Идея реализации была в том, чтобы выгрузка продолжала работать через типовые средства при помощи БСП, но в случае необходимости, делала это частями.

Реализация

Собственно, сам алгоритм получился примерно следующий:

Блок схема

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

2.      Если количество зарегистрированных изменений по справочникам больше чем установлено в ограничении, то сначала порционно выгружаются данные из справочников. Справочники выгружаются в первую очередь, чтобы между выгрузкой справочников и регистров в регистрах не было «Объект не найден»

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

Может возникнуть вопрос, почему не выгружать одновременно справочники и регистры, если количество зарегистрированных изменений не превышает ограничение. Ответ кроется в функции ВыбратьИзменения у менеджера плана обмена. Что она собственно делает? Описание из синтаксис помощника 1С:Предприятие:

Синтаксис:

ВыбратьИзменения(<Узел>, <НомерСообщения>, <ФильтрВыборки>)

«Формирует выборку измененные данные для передачи их в тот или иной узел плана обмена. При этом в процессе выборки изменений в записи регистрации изменений проставляется номер сообщения обмена данными, в котором должны передаваться изменения. Номер сообщения в записи регистрации проставляется для того, чтобы при подтверждении приема сообщения, в котором передавались изменения соответствующие записи регистрации изменений были удалены и в дальнейшем изменения больше не передавались.»

В чем ее смысл – она выбирает измененные данные (зарегистрированные изменения) и проставляет в записи регистрации изменений номер сообщения обмена данными. Нам же нужно ограничить выборку определенным количеством объектов. В описании к данной функции есть важное замечание к 3 параметру «ФильтрВыборки»:

Неопределено - фильтр пуст, выбираются все изменения по узлу;
ОбъектМетаданных - выбираются изменения в основной таблице, связанной с данным объектом метаданных;
СсылкаНаОбъект - фактически, может быть выбрана только одна запись об изменении данного объекта, либо ни одной, если объект не менялся;
НаборЗаписей - набор записей регистра, может быть не выбран, для фильтрации изменений используется лишь отбор набора записей;
Массив - все элементы массива имеют один из перечисленных выше типов, кроме Неопределено. Условия фильтрации соединяются по ИЛИ.
Значение по умолчанию: Неопределено.

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

Все изменения добавляются в обработку «КонвертацияОбъектовИнформационныхБаз» в модуль объекта в процедуру «ВыполнитьВыгрузкуЗарегистрированныхДанных» после строки:

«НачальнаяВыгрузкаДанных = ОбменДаннымиСервер.УстановленПризнакНачальнойВыгрузкиДанных(ЗаписьСообщения.Получатель);»

До строки кода, которую тоже необходимо заменить:

ВыборкаИзменений = ОбменДаннымиСервер.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения, МассивВыгружаемыхМетаданных);  

В планы обмена необходимо добавить реквизит "КоличествоОбъектовВыгрузки" с типом число и добавить его на форму, в тем планы обмена, где ограничение актуально.

Еще один важный и приятный нюанс, это то что код написан таким образом, что при изменении состава необходимого плана обмена, нет необходимости переписывать ниже приведенный код, т.к. в нем определяется входит ли в состав плана обмена измененный объект. Т.е. в случае добавления нового объекта в состав плана обмена (или исключение), он будет автоматически добавляться (не добавляться, в случае исключения) в динамически формируемые запросы.

Собственно, сам код с комментариями.

	//Проверка на ограничение выгрузки данных за одну итерацию обмена данных
	//=======================================================================
	//получаем значение установленного ограничения
	КоличествоОбъектовКВыгрузке = ЗаписьСообщения.Получатель.КоличествоОбъектовВыгрузки;	
	//если ограничение установлено, то начинаем собирать запрос по объектам участвующим в обмене
	Если КоличествоОбъектовКВыгрузке <> 0 Тогда
		МассивДанныхДляОтбора = Новый Массив;
		ТекущийПланОбмена = Метаданные.ПланыОбмена[ЗаписьСообщения.Получатель.Метаданные().Имя];
		
		ТекстЗапросаОбщий = "";
		
		Для каждого СтрокаМетаданных Из ТаблицаПравилВыгрузкиИспользуемые Цикл
			СтрокаДляЗапроса = "";
			//для справочников формируем запрос с учетом того что там всегда есть Ссылка
			Если ЗначениеЗаполнено(СтрокаМетаданных.ИмяОбъектаДляЗапроса) И ТипЗнч(ТекущийПланОбмена.Состав.Найти(СтрокаМетаданных.ОбъектВыборкиМетаданные)) = Тип("ЭлементСоставаПланаОбмена") Тогда
				СтрокаДляЗапроса = СтрокаМетаданных.ИмяОбъектаДляЗапроса;
				
				//если это первый проход то указываем что это создание пакета
				Если ТекстЗапросаОбщий = "" Тогда
					ТекстЗапросаОбщий = ТекстЗапросаОбщий + "Выбрать ВД.Ссылка" + Символы.ПС + "ПОМЕСТИТЬ ВсеДанные" + Символы.ПС + " из " + СтрокаДляЗапроса + ".Изменения" + " КАК ВД ГДЕ ВД.Узел = &Узел" + Символы.ПС;
				Иначе
					ТекстЗапросаОбщий = ТекстЗапросаОбщий + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС + "Выбрать ВД.Ссылка из " + СтрокаДляЗапроса + ".Изменения" + " КАК ВД ГДЕ ВД.Узел = &Узел"  + Символы.ПС;
				КонецЕсли;
				
				//для регистров формируем запрос с учетом того что там разный набор измерений, но нам достаточно бырать Узел, чтобы подсчитать Количество объектов
				Если ЗначениеЗаполнено(СтрокаМетаданных.ИмяОбъектаДляЗапросаРегистра) И ТипЗнч(ТекущийПланОбмена.Состав.Найти(СтрокаМетаданных.ОбъектВыборкиМетаданные)) = Тип("ЭлементСоставаПланаОбмена") Тогда
					СтрокаДляЗапроса = СтрокаМетаданных.ИмяОбъектаДляЗапросаРегистра;
					//если это первый проход то указываем что это создание пакета
					Если ТекстЗапросаОбщий = "" Тогда
						ТекстЗапросаОбщий = ТекстЗапросаОбщий + "ВЫБРАТЬ ПЕРВЫЕ " + Формат(КоличествоОбъектовКВыгрузке, "ЧГ=0") + " Узел ПОМЕСТИТЬ ВсеДанные ИЗ " + СтрокаДляЗапроса + ".Изменения ГДЕ Узел = &Узел";					
					Иначе	
						ТекстЗапросаОбщий = ТекстЗапросаОбщий + "ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ПЕРВЫЕ " + Формат(КоличествоОбъектовКВыгрузке, "ЧГ=0") + " Узел ИЗ " + СтрокаДляЗапроса + ".Изменения ГДЕ Узел = &Узел";
					КонецЕсли;	
				КонецЕсли;			
			КонецЕсли;
		КонецЦикла; 
		
		//добавляем выборку данных
		ТекстЗапросаОбщий = ТекстЗапросаОбщий + Символы.ПС + "; ВЫБРАТЬ ПЕРВЫЕ " + Формат(КоличествоОбъектовКВыгрузке, "ЧГ=0") + 
		" ВсеДанные.Ссылка КАК ИзмененныйОбъект ИЗ ВсеДанные КАК ВсеДанные";
		
		ЗапросПоИзмененнымОбъектам = Новый Запрос(ТекстЗапросаОбщий);
		ЗапросПоИзмененнымОбъектам.УстановитьПараметр("Узел", ЗаписьСообщения.Получатель);
		ВыборкаПоИзмененнымОбъектам = ЗапросПоИзмененнымОбъектам.Выполнить().Выбрать();
		
		//получаем количество измененных объектов, которое в любом случае не будет больше ограничения, тем самым ускоряя выборку и проверку
		КоличествоЗарегистрированныхИзменений = ВыборкаПоИзмененнымОбъектам.Количество();
		
		//если количество зарегистрированных объектов = количеству объектов ограничения то нуобходимо ограничить выгрузку
		//проверка на "=" потому что все выборки ограничиваются количеством указанным в ограничении
		//или есди по справочникам не зарегистрировано изменений, то выгружаем РС если по ним есть что выгрузить
		Если КоличествоЗарегистрированныхИзменений = КоличествоОбъектовКВыгрузке ИЛИ КоличествоЗарегистрированныхИзменений = 0 Тогда
			//собираем запрос по изменениям из справочников
			ТекстЗапросаПоСправочникам = "";
			
			Для каждого СтрокаМетаданных Из ТаблицаПравилВыгрузкиИспользуемые Цикл
				СтрокаДляЗапроса = "";
				Если ЗначениеЗаполнено(СтрокаМетаданных.ИмяОбъектаДляЗапроса) И ТипЗнч(ТекущийПланОбмена.Состав.Найти(СтрокаМетаданных.ОбъектВыборкиМетаданные)) = Тип("ЭлементСоставаПланаОбмена") Тогда
					СтрокаДляЗапроса = СтрокаМетаданных.ИмяОбъектаДляЗапроса;
					
					Если ТекстЗапросаПоСправочникам = "" Тогда
						ТекстЗапросаПоСправочникам = ТекстЗапросаПоСправочникам + "Выбрать ПЕРВЫЕ " + Формат(КоличествоОбъектовКВыгрузке, "ЧГ=0") + " ВД.Ссылка" + Символы.ПС + "ПОМЕСТИТЬ ВсеДанные" + Символы.ПС + " из " + СтрокаДляЗапроса + ".Изменения" + " КАК ВД ГДЕ ВД.Узел = &Узел" + Символы.ПС;
					Иначе
						ТекстЗапросаПоСправочникам = ТекстЗапросаПоСправочникам + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС + "Выбрать ПЕРВЫЕ " + Формат(КоличествоОбъектовКВыгрузке, "ЧГ=0") + " ВД.Ссылка из " + СтрокаДляЗапроса + ".Изменения" + " КАК ВД ГДЕ ВД.Узел = &Узел"  + Символы.ПС;
					КонецЕсли;			
				КонецЕсли;
			КонецЦикла; 	
			//добавляем выборку данных
			ТекстЗапросаПоСправочникам = ТекстЗапросаПоСправочникам + "; ВЫБРАТЬ ПЕРВЫЕ " + Формат(КоличествоОбъектовКВыгрузке, "ЧГ=0") + " ВД.Ссылка ИЗ ВсеДанные КАК ВД"; 
			ЗапросПоИзмененнымДанным = Новый Запрос(ТекстЗапросаПоСправочникам);
			ЗапросПоИзмененнымДанным.УстановитьПараметр("Узел", ЗаписьСообщения.Получатель);
			
			//получаем данные с учетом ограничения которые будем выгружать
			МассивДанныхДляОтбора = ЗапросПоИзмененнымДанным.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
			
			//запоминаем сколько объектов всего выгрузили
			ВсегоВыгружено = МассивДанныхДляОтбора.Количество();
			
			ТекстЗапросаПоРегистрам = "";
			
			//если не было выгрузки справочников то в этой итерации можно выгрузить регистры
			Если ВсегоВыгружено = 0 Тогда		
				Для каждого СтрокаМетаданных Из ТаблицаПравилВыгрузкиИспользуемые Цикл
				//собираем запрос по изменениям из регистров
					СтрокаДляЗапроса = "";		
					
					Если КоличествоОбъектовКВыгрузке - ВсегоВыгружено = 0 Тогда
						Прервать;
					КонецЕсли;	 
					
					Если ЗначениеЗаполнено(СтрокаМетаданных.ИмяОбъектаДляЗапросаРегистра) И ТипЗнч(ТекущийПланОбмена.Состав.Найти(СтрокаМетаданных.ОбъектВыборкиМетаданные)) = Тип("ЭлементСоставаПланаОбмена") Тогда
						СтрокаДляЗапроса = СтрокаМетаданных.ИмяОбъектаДляЗапросаРегистра;
						                                                    
						ТекстЗапросаПоРегистрам = "ВЫБРАТЬ ПЕРВЫЕ " + Формат((КоличествоОбъектовКВыгрузке - ВсегоВыгружено), "ЧГ=0") + " * ИЗ " + СтрокаДляЗапроса + ".Изменения ГДЕ Узел = &Узел";
						
						Запрос = Новый Запрос(ТекстЗапросаПоРегистрам);
						Запрос.УстановитьПараметр("Узел", ЗаписьСообщения.Получатель);
						ИзмененныеДанные = Запрос.Выполнить().Выбрать();
						
						Если ИзмененныеДанные.Количество() > 0 Тогда
							Пока ИзмененныеДанные.Следующий() Цикл
								Если ВсегоВыгружено = КоличествоОбъектовКВыгрузке Тогда
									Прервать;
								КонецЕсли;
								
								//формируем пустые наборы записей, т.к. из них нужны отборы для корректной фильтрации данных
								Если Найти(СтрокаДляЗапроса, "РегистрСведений") <> 0 Тогда					
									Набор = РегистрыСведений[СтрЗаменить(СтрокаДляЗапроса, "РегистрСведений.", "")].СоздатьНаборЗаписей();
								ИначеЕсли Найти(СтрокаДляЗапроса, "РегистрНакопления") <> 0 Тогда	
									Набор = РегистрыНакопления[СтрЗаменить(СтрокаДляЗапроса, "РегистрНакопления.", "")].СоздатьНаборЗаписей();
								КонецЕсли;				
								
								//заполняем отборы данных в зависимости от измерения конкретного регистра
								Для каждого СтрокаОтбора Из Набор.Отбор Цикл
									//Добавляем попытку, т.к. в выборке из запроса могут быть не все поля, которое есть в отборе набора
									Попытка
										СтрокаОтбора.Установить(ИзмененныеДанные[СтрокаОтбора.ПутьКДанным]);
									Исключение
									КонецПопытки;
								КонецЦикла; 
								
								МассивДанныхДляОтбора.Добавить(Набор);
								
								Инкремент(ВсегоВыгружено);
							КонецЦикла; 
						КонецЕсли;	
						
					КонецЕсли;
					
				КонецЦикла; 	
				
			КонецЕсли;
	//=======================================================================			
	// ВЫБОРКА ИЗМЕНЕНИЙ 
			ВыборкаИзменений = ОбменДаннымиСервер.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения, МассивДанныхДляОтбора);
		Иначе   
			// если количество объектов справочников к выгрузке меньше ограничения, то выгружаем только справочники, т.к. по регистрам
			// может быть Количество объктов к выгрузке большем чем ограничение
			МассивМетаданныхСправочников = ТаблицаПравилВыгрузкиИспользуемые.НайтиСтроки(Новый Структура("ИмяОбъектаДляЗапросаРегистра", Неопределено));
			МассивВыгружаемыхМетаданных = Новый Массив;
			Для каждого СтрокаМассиваМетаданныхСправочников Из МассивМетаданныхСправочников Цикл
				МассивВыгружаемыхМетаданных.Добавить(СтрокаМассиваМетаданныхСправочников.ОбъектВыборкиМетаданные);	
			КонецЦикла; 
			
			ВыборкаИзменений = ОбменДаннымиСервер.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения, МассивВыгружаемыхМетаданных);	
		КонецЕсли;
	Иначе   	
		ВыборкаИзменений = ОбменДаннымиСервер.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения, МассивВыгружаемыхМетаданных);		
	КонецЕсли;

Про быстродействие

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

Ограничения

  1. Данный код проверялся только на Управление торговлей, редакция 11.2 (11.2.3.108) и БСП 2.3.2.50 и только в режиме передачи данных через Web - сервисы, по правилам, написанным в конвертации данных 2.1. Возможно в других конфигурация потребуется какая-то доработка кода, так же и в случае использования универсально формата обмена данными.
  2. Данный код рассчитан на то, что в составе плана обмена участвуют только справочники, регистры сведений и регистры накопления. Если в плане обмена участвуют другие объекты, то код потребует доработки.

Вместо заключения

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

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

Скачать файлы

Наименование Файл Версия Размер
КонвертацияОбъектовИнформационныхБаз
.epf 116,77Kb
31.01.17
4
.epf 116,77Kb 4 Скачать

См. также

Комментарии
1. Виктор Маркевич (warrior1985) 63 01.02.17 09:36 Сейчас в теме
2. DenisCh Гейтс (DenisCh) 01.02.17 09:43 Сейчас в теме
Я-то думал, будет что-то оригинальное...
А разбиение по кускам - это очевидное же решение...
3. Иван Шумкин (SinglCOOLer) 204 01.02.17 11:26 Сейчас в теме
4. Иван Шумкин (SinglCOOLer) 204 01.02.17 11:26 Сейчас в теме
(2) поэтому дисклеймер и написал
5. Олег Филиппов (comol) 3169 13.03.17 12:43 Сейчас в теме
Автор знает толк в извращениях.

Можно конечно и 60 тыс передать через web сервисы.. но зачем?

6. Игорь Полосков (ipoloskov) 57 13.03.17 13:08 Сейчас в теме
При решении аналогичной задачи, встал вопрос блокировки данных изменений. Как известно, план обмена блокирует таблицы изменений, начиная с операторов
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, УзелОбмена); 

и заканчивая
ЗаписьСообщения.ЗакончитьЗапись(); 

после последней строчки, соответственно, план обмена начинает писать изменения с Номером+1
Оставлять все в базе заблокированным между вызовами нельзя. Как вы решили эту проблему?
7. Олег Филиппов (comol) 3169 13.03.17 14:25 Сейчас в теме
(6) Эх, если бы этот вопрос был решен или хоть как то решался жизнь была бы настолько проще...

Вообщем если хотим передать кучу данных - пишем их тупо в файл на ftp - самый правильный и надежный способ.
Если хотим выбрать кучу изменений - исключаем их из общего РИБ-а и выделяем в отдельный узел... ну или свой механизм регистрации пишем
Если надо чтобы "оно само" - убираем обмены и в отельную СУБД (couchDB)
8. Игорь Полосков (ipoloskov) 57 13.03.17 15:31 Сейчас в теме
(7) я решил так:
мне надо было передавать документы и их печатные формы. В пакете выгрузки между НачатьЗапись и ЗакончитьЗапись я выгружал только документы, без печатных форм. Документы, хотя их и много, но объем данных в выгрузке образуют небольшой. Весь образованный объем данных без труда прокачивался за один вызов.
Следующими вызовами, по частям, я запрашивал печатные формы для заданного массива документов. Там уже план обмена не используется, и ничего не блокируется.

В экстремальных случаях, если даже данные документов слишком объемны для единоразовой прокачки, можно на первом этапе выгружать и передавать только их УИДы. А все данные получать потом, частями.
9. Иван Шумкин (SinglCOOLer) 204 14.03.17 11:01 Сейчас в теме
(5) Затем что есть FrontOffice на котором работают скидки и бонусы как в УТ 11, для их расчета нужно достаточно много информации
10. Иван Шумкин (SinglCOOLer) 204 14.03.17 11:03 Сейчас в теме
(6) Не сталкивались с такой проблемой, может у нас разная реализация, т.к. по сути дробление идет на верхнем уровне
11. Иван Шумкин (SinglCOOLer) 204 14.03.17 11:05 Сейчас в теме
(7) По моему вы как раз знаете толк в извращениях, ftp и в общем работа с файлами напрямую это лишняя и не нужная точка отказа, про РИБ вообще молчу, что то простите еще отдельную СУБД городить? Я останусь при своем мнении
12. Олег Филиппов (comol) 3169 14.03.17 14:53 Сейчас в теме
(11) А ограничения http протокола это не точка отказа? 6))))))))))). Будем проверять что надежнее ftp или web сервисы? :)))
13. Иван Шумкин (SinglCOOLer) 204 14.03.17 18:13 Сейчас в теме
(12) У нас уже все проверено, веб сервисы на бсп сами дробят файл + мы сами ограничиваем размер. Зачем нам на слабых компьютерах где работает касса грузить к примеру файл 4 гб или более? что будет с производительностью кассы в этот момент? или кассы надо будет делать на core i7 все с ssd. Как думаете что легче грузить? 4 и более гб за раз или порциями по 20 мб? Дак чем нам мешает ограничение?
14. борян петров (TODD22) 16 15.03.17 07:35 Сейчас в теме
(7)
Вообщем если хотим передать кучу данных - пишем их тупо в файл на ftp - самый правильный и надежный способ.

Как показывает практика не самый надёжный способ. У меня две сети магазинов. В одной ftp проработал 2 года. Неделю назад его перезагрузили. Теперь работает очень плохо.... файлы принимает через раз. Имена файлов кривые. Обмены проходят с 4-5 попытки.
Во второй сети такие же проблемы, то имена файлов кривые, то файл обмена с 3-4 попытки на ftp закидывает.


Но и с web сервисами как оказалось то же не всё гладко. Написал сервис передаёт маленькие xml. Из за плохого интернета очень часто подвешивает платформу.
Оставьте свое сообщение