|
![]() |
#1 |
Боец
|
это известная проблема X++, когда выполнение кода просто прерывается без возможности отлова исключений. Чаще всего происходит при вызовах внешнего кода.
Знаю два варианта решения: #1: На C# пишем простую функцию, которая вызывает внешний сервис (или, в общем случае, любой, потенциально нестабильный внешний код). Функция будет вызывать внешнюю 1:1 как бы вы это делали из X++. Но на C# вы делаете полноценный try/catch, который гарантированно вернет управление обратно в АХ. Функцию подключаем как .net reference в АОТ и юзаем. Это решение простое и надежное, правильное. Но получаем все нюансы использования .net references, что требует бережного обращения, в зависимости от версии АХ #2 реализовать класс MultithreadHandler, который: 1) запустит необходимое кол-во потоков в асинхронном режиме 2) периодически, опрашивая их статус, дождется их окончания 3) в зависимости от того, вернул поток результат, либо скоропостижно скончался (это можно отследить в классе Thread), залогирует соотвествующий результат. Тут правда, в отличие от первого способа, вы никогда не узнаете, от чего поток умер (или какое исключение вернул внеший вызов) #3 Гм, или я не понял задачу ![]() Последний раз редактировалось DSPIC; 13.11.2015 в 00:49. |
|
![]() |
#2 |
Участник
|
Спасибо за совет, идею понял. Если сформулировать точнее, то проблема заключается в следующем:
на вход импорт-класса я последовательно скармливаю XML-и, которые должны в определенной последовательности обрабатываться. Скажем, у меня есть 5 XML-ей: подал первую - скушал, подал вторую - скушал, на третьей подавился, выбросил ошибку, оборвал транзакцию, в итоге вся информация про 1-ю и 2-ю вместе с логами пропали, поскольку вызов сервиса происходит в контексте одной транзакции. Значит теоретически я могу, используя метод #2, для каждого прохода открыть новый поток и в нем новое соединение? Или все открываемые потоки будут обрабатываться как одна транзакция? |
|
![]() |
#3 |
Британский учённый
|
Если я правильно понял проблему, то я бы смотрел в сторону модификации AIF - так что бы каждый вызов внешнего класса выполнялся отдельной транзакцией, но это мне видится далеко не тривиальной задачей. К тому же, лог в этом случае, вероятно будет потерян. Другой вариант - изменить принцип логирования\обработки исключений во внешнем классе. Можно, например в случае исключения отсылать лог Аксапте через другой простенький AIF сервис.
__________________
Людям физического труда для восстановления своих сил нужен 7-8 часовой ночной сон. Людям умственного труда нужно спать часов 9-10. Ну а программистов будить нельзя вообще. Последний раз редактировалось Link; 16.11.2015 в 18:41. |
|
![]() |
#4 |
Модератор
|
Нельзя несколько вызовов AIF завернуть в некую внешнюю транзакцию. Но, как вариант, можно упаковать несколько документов в одно сообщение - смотрите в сторону Processing batched messages in AIF [AX 2012]
__________________
-ТСЯ или -ТЬСЯ ? |
|
![]() |
#5 |
Участник
|
Цитата:
можно упаковать несколько документов в одно сообщение
Цитата:
НО: если хоть где-то в коде выбросится ошибка или вызов ttsabort, то соответственно ни лога, ни данных...
Посмотрите как AIF вызывает ваш метод в AifWcfProcessor, сделайте трейс. И как транзакция открывается/закрывается - AifRequestProcessor.processWcfRequest - AIF делает ttsbegin в конце AifRequestProcessor.processWcfResponse - AIF делает ttscommit в начале Имейте ввиду что AIF логика может быть разная для Basic и Enhanced портов.
__________________
AxAssist 2012 - Productivity Tool for Dynamics AX 2012/2009/4.0/3.0 |
|
|
За это сообщение автора поблагодарили: Logger (1), sgt.Pepper (1), A_BAS (2). |
![]() |
#6 |
Участник
|
В методе который выполняется AIF запускайте thread.
|
|
![]() |
#7 |
Участник
|
Если кому интересно, нашел решение проблемы (спасибо подсказке Alex_KD).
При вызове сервиса AIF создает "глобальную" транзакцию, соттветственно если что-то случается в самом сервисе, все try-catch блоки самого сервиса просто игнорируются и идут выше в обработчики AIF, где собственно было начало транзакции. Все попытки использовать catch Error, ClrError, Internal и просто catch не увенчались успехом. Что сделано: в точке входа сервиса сделал проверку на уровень tts и сразу сделал ttscommit. X++: ttsInitialLevel = appl.ttsLevel(); if(ttsInitialLevel > 0) { ttscommit; ttsbegin; } ... После отработки метода делаю ttscommit своей транзакции, и перед возвратом создаю новую. X++: if(ttsInitialLevel >0 && appl.ttsLevel() == 0) ttsbegin; return something Последний раз редактировалось sgt.Pepper; 26.04.2016 в 20:43. |
|
|
За это сообщение автора поблагодарили: gl00mie (2). |