AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 16.03.2023, 11:36   #1  
Player1 is offline
Player1
Участник
Самостоятельные клиенты AX
 
305 / 137 (5) +++++
Регистрация: 21.04.2008
Расчет сводника
Добрый день.
Периодически (не каждый день) расчет сводника прерывается с ошибкой "Невозможно отредактировать запись в Чистые потребности (ReqTrans). Возник конфликт обновления из-за того, что другой пользовательский процесс выполняет удаление записи или изменение одного или нескольких полей в записи.", ну далее "Покрытие номенклатуры частично обновлено.", а у помощников соответственно "Главный процесс помечен как процесс, в котором произошел сбой".
АХ2009. Считаем с помощниками, кол-во пробовали менять, чаще используем 4-6 штук.
В методе ReqTrans.update() сделали стандартную конструкцию оптимист.модели, чтобы хоть что-то понять, а также поймать ошибку и вывести номенклатуру на которой крашится - не помогло, номенклатуры разные.
X++:
    catch (Exception::Deadlock)
    {
        retry;
    }
    catch (Exception::UpdateConflict)
    {
        if (appl.ttsLevel() == 0)
        {
            if (xSession::currentRetryCount() < #RetryNum)
            {
                retry;
            }
        }
        else
        {
            warning(strfmt("Ошибка при обновлении ном-ры %1", this.ItemId));
            throw Exception::UpdateConflict;
        }
Собственно главный вопрос по каким причинам в данном update может быть appl.ttsLevel() > 0 и это вообще нормально?

Стек расчета стандартный
X++:
(S)\Data Dictionary\Tables\ReqTrans\Methods\update,57,
(S)\Data Dictionary\Tables\ReqTrans\Methods\deleteExplosionCoverageTrans,19,
(S)\Data Dictionary\Tables\ReqTrans\Methods\deleteExplosionCoverage,53,
(S)\Classes\ReqCalc\deleteItemRequirement,69,
(S)\Classes\ReqCalcScheduleItemTable\insertDataRegeneration,88,
(S)\Classes\ReqCalcScheduleItemTable\insertData,23,
(S)\Classes\ReqCalc\updateDat,10,
(S)\Classes\ReqCalc\run,15,
(S)\Classes\ReqCalcScheduleItemTable\run,52,
(S)\Classes\ReqProcessExternThread\initAndRunReqCalc,15,
(S)\Classes\ReqProcessExternThread\run,27,
(S)\Classes\BatchRun\runJobStatic,63
Старый 16.03.2023, 12:02   #2  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,651 / 1158 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Нормально.

Exception::UpdateConflict не прерывает транзакцию (поэтому appl.ttsLevel() > 0) и обрабатывается "ближайшим" try..catch внутри транзакции. Поэтому при обработке этого исключения в catch делают перехват и вызов другого типа исключения Exception::UpdateConflictNotRecovered

Посмотрите пример в классе \Classes\Tutorial_RunbaseBatch\run

То же самое справедливо и для Exception::DuplicateKeyException

Try Catch в методе update на таблице
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
За это сообщение автора поблагодарили: Player1 (1).
Старый 16.03.2023, 12:48   #3  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,890 / 5647 (194) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
В общем - дело давнее: Насколько я помню, в стандартном сводном DAX2009 была бага, связанная с кэшированием чистых потребностей. Когда происходит вызов reqTrans.update() туда как второй (насколько я помню) параметр передается ссылка на класс ReqTransCache, где кэш с чистыми потребностями хранится. И после обновления, reqTrans.update() складывает в reqTransCache обновленную копию записи.

При этом где-то как раз в недрах методов deleteExplosionCoverage и deleteExplosionCoverageTrans этот второй параметр не передается и в reqTransCache остаются необновленные данные, при использовании которых и случается updateConflict. (На самом деле - там не update conflict в чистом виде, а просто попытка записать в БД устаревшую копию записи, с неверным recVersion). Я это лечил простым способом - при вызове цепочки deleteExplosion() я новым параметром передавал ReqTransCache и дальше передавал его глубже в reqTrans.update() (и возможно в reqTrans.delete() и reqTrans.insert() - я уже не помню есть там такой параметр или нет). После того как я это сделал, проблема вылечилась и система у клиента уже 12 лет работает.

P.S. Поправка - судя по коду D365FO передается не reqTransCache, а reqPlanData. Но из reqPlanData внутри update вынимается ReqTransCache и туда обновленные данные складываются. Но в целом - подход к решению это не меняет. Над убедится что из deleteExplosion* в метод update передается ссылка на правильный класс.

Последний раз редактировалось fed; 16.03.2023 в 12:52.
За это сообщение автора поблагодарили: Player1 (5).
Старый 16.03.2023, 14:55   #4  
Player1 is offline
Player1
Участник
Самостоятельные клиенты AX
 
305 / 137 (5) +++++
Регистрация: 21.04.2008
Цитата:
Сообщение от fed Посмотреть сообщение
В общем - дело давнее: Насколько я помню, в стандартном сводном DAX2009 была бага, связанная с кэшированием чистых потребностей. Когда происходит вызов reqTrans.update() туда как второй (насколько я помню) параметр передается ссылка на класс ReqTransCache, где кэш с чистыми потребностями хранится. И после обновления, reqTrans.update() складывает в reqTransCache обновленную копию записи.

При этом где-то как раз в недрах методов deleteExplosionCoverage и deleteExplosionCoverageTrans этот второй параметр не передается и в reqTransCache остаются необновленные данные, при использовании которых и случается updateConflict. (На самом деле - там не update conflict в чистом виде, а просто попытка записать в БД устаревшую копию записи, с неверным recVersion). Я это лечил простым способом - при вызове цепочки deleteExplosion() я новым параметром передавал ReqTransCache и дальше передавал его глубже в reqTrans.update() (и возможно в reqTrans.delete() и reqTrans.insert() - я уже не помню есть там такой параметр или нет). После того как я это сделал, проблема вылечилась и система у клиента уже 12 лет работает.

P.S. Поправка - судя по коду D365FO передается не reqTransCache, а reqPlanData. Но из reqPlanData внутри update вынимается ReqTransCache и туда обновленные данные складываются. Но в целом - подход к решению это не меняет. Над убедится что из deleteExplosion* в метод update передается ссылка на правильный класс.
Хмм, спасибо огромное, но судя по всему всё так и передается
В ReqTrans.update()
X++:
public server void update(ReqPlanData _reqPlanData = null,
                          boolean _reduceCovQty = true)
{
    ReqTransCache           reqTransCache = _reqPlanData ? _reqPlanData.reqTransCache() : null;
а после super()
X++:
    if (reqTransCache)
        reqTransCache.update(this);
Методы deleteExplosionCoverage(Trans) просто протаскивают через себя необязательный параметр
X++:
server void deleteExplosionCoverageTrans(ReqPlanData     _reqPlanData             = null)
Ну а по стеку эта цепочка начинается в ReqCalc.deleteItemRequirement(), но там идет передача
X++:
        if (reqTrans.isDerivedDemand())
        {
            // reqTrans has to be updated but it could be it has been derived deleted by the previous record in this select statement
            // we need to ensure the record still exists
            if (   reqTransCache.exists(reqTrans)
                || ReqTrans::findRecId(reqTrans.RecId).RecId)
            {
                reqTrans.CovQty = 0;
                reqTrans.update(reqPlanData);
            }
        }
        else
        if (reqTrans.isPlannedOrder())
        {
            setupDim = reqPlanData.newReqSetupDim(_setup,reqTrans.CovInventDimId);

            if (reqPlanData.mustKeepPlannedOrder(setupDim,reqTrans,setApprovedPlannedOrder))
            {
                reqTrans.CovQty      = 0;
                reqTrans.update(reqPlanData);
            }
            else
            {
                reqTrans.deleteExplosionCoverage(reqPlanData);
                doDelete = true;
            }
        }
        else
            doDelete = true;
Не понятно когда reqPlanData пустым передается
Старый 16.03.2023, 15:42   #5  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,890 / 5647 (194) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
Как идея: Попробуйте поставить в reqTrans.update() if(reqTransCache==NULL) breakpoint и посмотрите откуда этот метод без кэша вызывается при сводном планировании.
Возможно еще, что проблема происходит внутри класса ReqTransUpdate. Оно там точно reqTrans обновляет/удаляет/вставляет и, насколько я помню, делает это без reqPlanData. При этом класс этот вызывается при обработке очередной номенклатуры в ReqCalc и возможно это туда надо reqPlanData передавать. (Но может быть это у меня ложные воспоминания).
Я просто точно помню что у меня на проекте возникали точно такие же проблемы с обновлением из deleteExplosion и это точно было вызвано неактуальным кэшем.
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Расчет себестоимости в разрезе Сайта Anya DAX: Функционал 20 30.01.2020 09:21
Расчет себестоимости номенклатуры Anya DAX: Функционал 12 23.12.2019 10:26
Расчёт цены номенклатуры raniel DAX: Функционал 10 28.03.2014 09:48
Альтернативные рабочие центы и расчет потребления по формуле мощность Starling DAX: Функционал 0 25.08.2010 14:13
Русская локализация Axapta 3 ? SlavaK DAX: Администрирование 59 01.07.2003 22:38
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 02:17.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.