|
31.01.2019, 11:29 | #1 |
Участник
|
Как правильно? куда вставить действия при старте AOS? ax2009, ax2012 и прочие версии
Disclaimer:
Обратите внимание, вопрос сформулирован "Как правильно?" На проекте задача уже решена. Поэтому, пожалуйста, не уводите тему в сторону "быстрых и грязных решений". Задача: = Обновить параметры интеграции с 1С = Обновить url в references внешних вебсервисов = Обновить параметры после рестора рабочей базы в текстовую или другие подобные действия, которые надо выполнить один раз после останова всех кластерных АОСов, но до старта обычных сессий. Вопросы: Куда лучше вставить вызов таких действий? Какими условиями стоит обставить вызов? Какие условия стоит учесть при вызове таких действий? См. также: ClientType::Server Является ли текущее приложение рабочим или тестовым Что получилось исследовать на ax2009:
получается, что в Application.new() вставится можно. Но в этом месте аксапта еще не инициализирована, поэтому в этом месте слишком много ограничений. Альтернативный вариант: предположим, мы решили использовать lazy-инициализацию и дожидаемся пока кто-то запустит неинициализированный функционал, и в момент запуска проверяем была ли выполнена инициализация и инициализируем если нужно. но инициализация может выполняться достаточно долго (несколько секунд при старте АОС роли не играет, а несколько секунд ожидания при работе клиентов - критично) поэтому с lazy-инициализацией с огромной вероятностью получим гонку за ресурсом. следовательно надо будет устраивать какой-то мьютекс и решать прочие параллельные проблемы. Но вдруг кто-то и так решал? Плюсы-минусы? В общем, Куда вставить свой код инициализации/обновления так, чтобы он сработал после инициализации AOS, но до запуска остальных сессий? Последний раз редактировалось mazzy; 31.01.2019 в 11:51. |
|
|
За это сообщение автора поблагодарили: alex55 (1). |
31.01.2019, 12:16 | #2 |
Участник
|
Цитата:
Сообщение от mazzy
Что получилось исследовать на ax2009:
...
получается, что в Application.new() вставится можно. Но в этом месте аксапта еще не инициализирована, поэтому в этом месте слишком много ограничений. В общем, Куда вставить свой код инициализации/обновления так, чтобы он сработал после инициализации AOS, но до запуска остальных сессий? В Application.new в конце писал код X++: if (session.clientKind() == ClientType::Server && session.sessionId() == 2) { ... // мой код } |
|
|
За это сообщение автора поблагодарили: mazzy (2), sukhanchik (3). |
31.01.2019, 12:32 | #3 |
Участник
|
Цитата:
насколько я понимаю, пакеты могут стартовать после пользовательских сессий, а могут не стартовать вообще, если в SysServerConfig уже есть текущий сервер и он не помечен галочкой пакетный. можно ли гарантировать, что 2-я служебная сессия гарантировано запускается до пользовательских? можно ли гарантировать, что на момент запуска 2-й служебной сессии существуют гломальные переменные appl, infolog, classFactory, кэши, транзакции и прочие системные механизмы? |
|
31.01.2019, 12:40 | #4 |
Участник
|
Цитата:
Про глобальные переменные уже не помню. Надо пробовать. Но там однозначно все лучше чем с первой сессией, которая например по curExt() выдает пустую строку (даже не "dat" и соответственно не может ничего вставить в неглобальную табличку) |
|
|
За это сообщение автора поблагодарили: mazzy (5), gl00mie (5). |
31.01.2019, 16:30 | #5 |
Участник
|
Цитата:
Сообщение от Logger
Можно гарантировать что 2-я сессия точно запустится до старта пакетов независимо от того помечен аос как пакетные или нет. Насчет клиентских сессий - похоже что да. Это можно проверить просто выводов в виндовый лог сообщения - посмотреть когда оно появляется до сообщения аоса о том что он стартовал или после.
Про глобальные переменные уже не помню. Надо пробовать. Но там однозначно все лучше чем с первой сессией, которая например по curExt() выдает пустую строку (даже не "dat" и соответственно не может ничего вставить в неглобальную табличку) да, curext() заработал. но глобальные переменные еще не проинициализированы. в общем, очень хочется какой-нибудь метод после инициализации, но до запуска остальных сессий. |
|
31.01.2019, 13:00 | #6 |
Участник
|
Возможно оффтоп но ...
Цитата:
= Обновить параметры интеграции с 1С
= Обновить url в references внешних вебсервисов Конечный итог - AX обновляется одинаково в QA/UAT/Prod и релиз сводится к нажатию кнопки и к проверке что все зеленое (что может сделать кто-то далекий от AX и кто не спит по ночам). Для 2009 startup команды работают и можно дописать свои. Что-то типа - Цитата:
ax32.exe -startupcmd=AOTImport_"C:\AX\Import\File.xpo"
Цитата:
= Обновить параметры после рестора рабочей базы в текстовую
__________________
AxAssist 2012 - Productivity Tool for Dynamics AX 2012/2009/4.0/3.0 |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
31.01.2019, 13:08 | #7 |
Участник
|
Цитата:
я думал о том, чтобы использовать механизм ReleaseUpdate для таких действий. Но на проектах версию приложения обновляют практически никогда Если же на проекте настроен CI в каком-либо виде, то дожидаться старта АОС действительно не обязательно. Цитата:
Беда в том, что startupcmd выполняется в application.startup() который, в свою очередь не выполняется при старте АОС (см. первое сообщение в этой ветке) ax32.exe - это уже поздно. хотелось бы вставиться в момент запуска ax32serv.exe |
|
31.01.2019, 13:11 | #8 |
Участник
|
Нет, конечно.
Разбираться средствами SQL с содержимым полей типа container... Нет К тому же рестор прода в тест может выполняться не только ночью. Но и по требованию консультантов. |
|
31.01.2019, 14:03 | #9 |
Участник
|
пообедал и вспомнил, что не рассказал о стартап-команде autorun
да, это первое что приходит в голову. особенно действие run. да, команда autorun (как и остальные startup-команды) выполняется при запуске клиента ax32.exe и не выполняется при запуске сервера ax32serv.exe чтобы работать с этой командой, нужно гарантировать, что аксапта до завершения этой команды не пустит пользователей и не будет запускать пакетные задания из очереди. получается какой-то хлипкий скрипт, завязанный на кучу событий и статусов, который легко сломать одним неловким движением администратора. поэтому от варианта с autoRun отказались сразу. но может кто-нибудь таки реализовал этот способ? |
|
31.01.2019, 14:18 | #10 |
Banned
|
Если подняться на уровень выше то AOS это Windows service.
Задача стоить выполнить некий script перед запуском windows service. Идеально оформить повторяемую задачу в виде новой windows service которая будет читать некий скрипт или файл параметров. Настроить как dependencies между этой новой службой очистки и AOS. Может выглядить overkill но архитектурно самое прямое решение. Цитата:
Обновить параметры интеграции с 1С
= Обновить url в references внешних вебсервисов = Обновить параметры после рестора рабочей базы в текстовую |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
31.01.2019, 14:34 | #11 |
Участник
|
Цитата:
но с дополнительными условиями: = новая служба должна работать с полями типа контейнер (любят, блин, хранить данные в контейнерах) = новые администраторы, которые будут рано или поздно придут, не должны сломать эту хитрую систему. пока мне кажется, что по-правильному эта штука должна быть внутри аксапты и выполняться до запуска пользовательских сессий и пакетников. |
|
31.01.2019, 14:56 | #12 |
Banned
|
Пока вижу что сообщество пытается по кривому в Application.New
if (session.clientKind() == ClientType::Server && session.sessionId() == 1) { } Еще бы я бы брал в расчет что код один на несколько AOS. И может быть одновременный/последовательный запуск. Добавлю что в AX2012 те же number sequence уже не загружаются при старте приложения, то есть инициализация отличается от AX2009. Ну и все же я бы посмотрел как с контейнерами работать на стороне SQL. Некомфортная зона для нас, да. Но это не значит что так не будет проще. Если все упирается в только контейнеры, то я бы помучился с T-SQL. |
|
31.01.2019, 15:07 | #13 |
Участник
|
не то, чтобы "пытается".
многоуважаемые кроты не видят другого способа Цитата:
https://www.youtube.com/watch?v=s44X6l-MgGY угу. ax_mct, я ж два пункта написал. расскажите, как хитрый скрипт сможет гарантировать что он сработает до клиентов и пакетников, и при этом его не сломают новые администраторы со своими скриптами, WMI'ями и прочими кубернетиками |
|
31.01.2019, 17:23 | #14 |
Banned
|
Цитата:
Цитата:
Задача:
= Обновить параметры интеграции с 1С = Обновить url в references внешних вебсервисов = Обновить параметры после рестора рабочей базы в текстовую или другие подобные действия, которые надо выполнить один раз после останова всех кластерных АОСов, но до старта обычных сессий. Так вот правильно, с инженерной точки зрения. не лезть в код приложения, а использовать скрипт Power Shell/T-SQL. Службы стоят, база ресторится, запускается скрипт сброса живых значений. Идеально если скрипт рестора содержит также запуск этого скрипта. То есть часть скрипта копирования базы. Понятно что X++ роднее чем T-SQL но в данном случае обратная ситуация той когда люди не знают X++ и используют T-SQL для бизнес-логики. Здесь у нас задача сбросить/изменить значения в базе. Для базы, на уровне базы. Без бизнес-логики. Помещать код в Application от кривых рук администраторов - не правильно. |
|
31.01.2019, 17:43 | #15 |
Участник
|
Цитата:
не работает. а xClassFactory.new объявлен как final Цитата:
смотрю на инициализацию AIF в 2009 и в 2012 - громадные отличия в части инициализации. Может же майкрософт сделать, когда им это нужно. значит, servicesStartup, а не startupServices, чтобы к остальным поближе. Как это мило. Цитата:
Каковы ваши гарантии, что я сам не забуду о "скрипте рестора" через пару месяцев? Пока вы не предложите способ, работающий гарантировано, нахер ваши рассуждения о людях. https://www.youtube.com/watch?v=zvEfaU0gQuU Последний раз редактировалось mazzy; 31.01.2019 в 17:45. |
|
31.01.2019, 19:30 | #16 |
Banned
|
Цитата:
Сообщение от mazzy
Скрипт рестора?! И каковы ваши гарантии, что администраторы будут запускать скрипт рестора, а не сделают рестор руками или сваяют свой скрипт? Каковы ваши гарантии, что я сам не забуду о "скрипте рестора" через пару месяцев? Пока вы не предложите способ, работающий гарантировано, нахер ваши рассуждения о людях. https://www.youtube.com/watch?v=zvEfaU0gQuU Тема LIVE ссылок в копии она всем известная и понятная. И консультанту как заказчика действия, и исполнителю в поддержке. Там еще и SSRS и EP и AIF и... И все как-то привыкли решать это скриптом. На всех проектах. Уже много лет. Я поддерживаю задачу как учебную, она интересная. Но абсолютно против такого подхода на живом проекте. |
|
31.01.2019, 16:40 | #17 |
Участник
|
Ну ...
А что мешает вклинить такой код в new classFactory / Info Вдруг помогет. Теоретически, они должны позже инициализироваться чем Application но до других сессий. |
|
31.01.2019, 16:49 | #18 |
Участник
|
А там где сервисы AIF запускаются (метод servicesStartup в Application) уже есть что нужно?
По крайней мере транзакции там уже используются, да и AifInfoLog использует обычный infolog. |
|
|
За это сообщение автора поблагодарили: mazzy (5). |
31.01.2019, 18:10 | #19 |
Участник
|
и я забыл показать как выглядит servicesStartup в ax2012.
запишу сюда, чтобы вспомнить, когда через некоторое время сам набреду на эту ветку в поисках решения ключевой момент - посмотреть как инициализируется AIF и сделать также. servicesStartup в ax2012 запускается только для 1 сессии АОС. в этот момент еще не работает curext и, похоже, не заполнены таблицы SysClientSessions, SysServerSessions, SysClientServerSessions. для ax2009 хорошего решения, похоже, нет. но будем искать. |
|
31.01.2019, 18:49 | #20 |
Участник
|
SysClienSession для случаев ClientType::Server не создается. Наткнулся на это при попытке логировать вызовы BatchRun, хотел как раз пользоваться Session::getAOSInstance - возвращался пустой.
А вот SysServerSessions возможно есть (для BatchRun точно создается), для при логирования создал в Session метод без объединения с SysClienSession: X++: static server ServerId getAOSName() { SysServerSessions serverSessions; ; xSession currentSession = new xSession(); SkipAOSValidationPermission skipAOS; ; skipAOS = new SkipAOSValidationPermission(); skipAOS.assert(); //BP deviation documented serverSessions.skipAosValidation(true); select firstOnly AOSId from serverSessions where serverSessions.ServerId == currentSession.serverId(); return serverSessions.AOSId; } |
|
Теги |
как правильно |
|
|