21.06.2013, 09:49 | #1 |
Banned
|
AX2012 services - async. HTTP
Добрый день, кому-нибудь удавалось запустить WCF-HTTP-адаптер в AX2012 в асинхронном режиме, чтобы сначала принимал запрос, сохранял в очереди, а отвечал отдельно, когда есть ресурсы?
Кто-нибудь делал исходящий HTTP адаптер (на базе XMLHTTPRequest, к примеру)? |
|
22.06.2013, 06:59 | #2 |
Участник
|
Мы ajax'емся к WCF (inbound port) и тянем данные на веб страницу.
Делаем через промежуточный WCF, т.к. напрямую были какие то проблемы плюс нам надо ответ в виде JSON, а не XML. Ответ из AX опять же проще обработать в .NET. По производительности получаем дополнительные 40-100мс на запрос, что вполне терпимо. Дополнительно, когда inbound port добавляешь в Service Reference в Visual Studio проекте получаешь две функции, например MyFunc и MyFuncAsync. Может тебе просто надо 2ю функцию дернуть?
__________________
AxAssist 2012 - Productivity Tool for Dynamics AX 2012/2009/4.0/3.0 |
|
|
За это сообщение автора поблагодарили: EVGL (10), Kabardian (4). |
24.06.2013, 16:08 | #3 |
Banned
|
Alex_KD - 10 points!
Сказал Visual Studio "Generate async. calls", написал вот такой код - работает! Код: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace VendGroupUpdate { class Program { static void Main(string[] args) { VendGroupService.CallContext context = new VendGroupService.CallContext(); VendGroupService.EntityKey[] keys; VendGroupService.KeyField keyField; VendGroupService.AxdVendGroup vendGroup; DateTime timeNow; IAsyncResult result; int i; AsyncCallback cb = new AsyncCallback(Program.VendGroupCallback); ; context.Company = "USMF"; for (i = 1; i <= 1000; i++) // Try 1000 parallel calls { VendGroupService.VendGroupServiceClient client = new VendGroupService.VendGroupServiceClient(); client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Anonymous; keys = new VendGroupService.EntityKey[1]; keys[0] = new VendGroupService.EntityKey(); keyField = new VendGroupService.KeyField(); keyField.Field = "VendGroup"; keyField.Value = "10"; keys[0].KeyData = new VendGroupService.KeyField[1] { keyField }; vendGroup = new VendGroupService.AxdVendGroup(); vendGroup.VendGroup = new VendGroupService.AxdEntity_VendGroup[1]; vendGroup.VendGroup[0] = new VendGroupService.AxdEntity_VendGroup(); vendGroup.VendGroup[0].VendGroup = "10"; vendGroup.VendGroup[0].Name = i + " " + System.DateTime.Now.ToShortTimeString(); vendGroup.VendGroup[0]._DocumentHash = "XYZ"; vendGroup.VendGroup[0].action = VendGroupService.AxdEnum_AxdEntityAction.replace; try { timeNow = System.DateTime.Now; Console.WriteLine("Start call " + i); //client.update(context, keys, vendGroup); result = client.Beginupdate(context, keys, vendGroup, null/*cb*/, client); Console.WriteLine("Call ended. Acknowledge: " + result.AsyncState.ToString()); Console.WriteLine("Delay: " + (-timeNow.Subtract(System.DateTime.Now)).ToString()); } catch (Exception e) { Console.WriteLine("Exception: " + e.Message); client.Abort(); } //client.Close(); } Console.ReadKey(); } public static void VendGroupCallback(IAsyncResult ar) { VendGroupService.VendGroupServiceClient client = (VendGroupService.VendGroupServiceClient) ar.AsyncState; client.Endupdate(ar); Console.WriteLine("Callback fired."); } } } Последний раз редактировалось EVGL; 24.06.2013 в 17:52. |
|
26.06.2013, 02:25 | #4 |
Участник
|
Добрый день EVGL , пардон за много букв, надеюсь мои размышления окажутся хоть сколько-нибудь полезными.
Я правильно понимаю, что у вас проблема с обработкой реквестов на стороне аксапты, т.е кол-во реквестов в единицу времени не слишком большое но каждый реквест выполняется очень долго? И судя по вопросу вы готовы вкладываться в разработку которая позволит клиенту отложено понимать что запрос на сервере выполнен. Если да то можете рассмотреть следующий варианты (я привел все пару самых незамысловатых хотя на практике их гораздо больше) раз аксапта разработчики начинают активно использовать дот.нет. Если нет то поясните в чем у вас техническая трудность? Как говорил Alex_KD тут нужно использовать промежуточный WCF, так как сервисы акспаты несколько урезаны с точки зрения технической функциональности.
Вообще http устроен как протокол без состояний это дает наибольшую производительность, т.е. сервер не хранит состояние в памяти между вызовами клиента, а практически любая вещь (не считая кода 100 Continue) связанная с сессией (о том что сервер как бы помнит что это за клиент, храня его состояние в памяти постоянно) уже строится поверх http и снижает производительность. Что касается «асинхронных http» запросов, которые вы можете делать через .net это конечно асинхронно только со стороны клиента. Клиент, делая вызов асинхронно может не ждать ответа от сервера, а продолжать исполнять код текущего потока, а ответ, который сервер обработал синхронно, приходит в другой поток клиента, после чего он становиться доступен в пользовательском обработчике. В общих чертах это можно найти здесь |
|
|
За это сообщение автора поблагодарили: EVGL (10), Logger (1). |
26.06.2013, 11:36 | #5 |
Banned
|
Благодарю за глубокий ответ.
Цитата:
Сообщение от hardcore
Я правильно понимаю, что у вас проблема с обработкой реквестов на стороне аксапты, т.е кол-во реквестов в единицу времени не слишком большое но каждый реквест выполняется очень долго? И судя по вопросу вы готовы вкладываться в разработку которая позволит клиенту отложено понимать что запрос на сервере выполнен.
Цитата:
Сообщение от hardcore
Развернуть wcf сервис над ах, развернуть wcf сервис на клиенте. Клиент вызывает сервис над ах, асинхронно (имеется ввиду стандартный для .net подход
Цитата:
Сообщение от hardcore
Способ в лоб: То вы можете также вызвать клиентом сервис над ах из него запустить операцию в ах асинхронно, по завершении выполнения просто сохранять результат в сериализованнов виде например в базе. А клиент должен периодически опрашивать сервер. Минусы подхода со стороны клиента, что придется писать логику повторного забора результата.
Цитата:
Сообщение от hardcore
Клиент, делая вызов асинхронно может не ждать ответа от сервера, а продолжать исполнять код текущего потока, а ответ, который сервер обработал синхронно, приходит в другой поток клиента, после чего он становиться доступен в пользовательском обработчике. В общих чертах это можно найти здесь
|
|
26.06.2013, 14:21 | #6 |
Модератор
|
А на Azure Service Bus adapter не смотрели еще? Там вроде и Service reference при разработке клиента, и реальная асинхронность. Я не агитирую, просто интересно (возможно сами скоро будем тестировать)
__________________
-ТСЯ или -ТЬСЯ ? |
|
|
За это сообщение автора поблагодарили: EVGL (5). |
26.06.2013, 14:43 | #7 |
Banned
|
Цитата:
Сообщение от Vadik
А на Azure Service Bus adapter не смотрели еще? Там вроде и Service reference при разработке клиента, и реальная асинхронность. Я не агитирую, просто интересно (возможно сами скоро будем тестировать)
|
|
26.06.2013, 16:01 | #8 |
Участник
|
Цитата:
Цитата:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
Цитата:
Этого хотелось бы избежать, поскольку надстройка неминуемо скроет WSDL-описание
Цитата:
Совершенно верно. Опыт на моем компьютере показал, что доставка сообщения через все уровни абстракции занимает 30 мс, тогда как полная обработка простейшего запроса требует 2 с. Клиент требует ответ <1с.
Евгений, а в вашем примере с 1000 паралельными запросами все ли запросы действительно выполнились паралельно? Все ли запросы выполнились в примерно одинаковый промежуток времени? Что-то мне подсказывает, что первые 200 прошли на ура, а дальше пошел беспредел...
__________________
AxAssist 2012 - Productivity Tool for Dynamics AX 2012/2009/4.0/3.0 |
|
30.06.2013, 00:57 | #9 |
Участник
|
Цитата:
Сообщение от EVGL:
Этого хотелось бы избежать, поскольку надстройка неминуемо скроет WSDL-описание, а клиент предъявляет высокие требования к администрированию и контролю версий схем и моделей данных. В противном случае можно сразу брать MSMQ-адаптор и не мучиться. Цитата:
Сообщение от Alex_KD:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] Может есть какой метод с помощью которого можно прописать этот (или любой) аттрибут для AX сервиса? Моя же мысль была что можно воспользоваться преимуществами дот.нет которые дают простой в использовании патерн асинхронного программирования + сессионность wcf, а именно отпускать клиента раньше чем завершилась обработка вызова, а клиент справляясь о результатах всегда попадет на тот же инстанс сервиса который все об обработки этого запроса знает. На х++ пришлось бы запускать отдельный поток на каждый вызов сервиса, и вручную делать синхронизацию между потоками, и т.д. (много нюансов), либо написать небольшую инфраструктуру, вроде очереди куда класть задания, возвращать ответ и пакетником их обрабатывать, в любом случае кода кажется больше придется написать. |
|
19.07.2013, 09:55 | #10 |
Banned
|
В продолжение разговора: прилагаю рабочий outbound HTTP Adapter с тестовым сервером впридачу:
SharedProject_AIF_HTTP_Response.xpo TestHTTPListener_CS.xpo |
|
|
За это сообщение автора поблагодарили: Logger (5), gl00mie (5), Kabardian (4). |
12.10.2015, 18:41 | #11 |
Модератор
|
Случайно забрел сюда повторно. Понимаю что Евгению не сильно актуально, но вдруг кому-то пригодится.. Для "тяжелых" в плане количества участвующих таблиц и полей документов (типа клиента, поставщика, продукта) использование data policies с отключением ненужных (неиспользуемых) полей снижает время отклика как раз где-то раза в два-три
__________________
-ТСЯ или -ТЬСЯ ? |
|
|
За это сообщение автора поблагодарили: Link (1), gl00mie (2), kpoxa (1). |
Теги |
aif, ax2012, azure service bus, document service, service, законченный пример, производительность |
|
Опции темы | Поиск в этой теме |
Опции просмотра | |
|