Jump to content

UNIGUI как вэб сервис


Kenneth

Recommended Posts

Всем привет!

Возник такой вопрос, могу ли я использовать UNIGUI как RestFul Api? 

В ServerModule есть возможность принимать запросы ПОСТ, ГЕТ с параметрами и в принципе технически, я так понял, можно принять запрос с параметрами, обратиться к базе и обратно вернуть JSON ответ. Я все это уже сделал и в принципе все неплохо работает, но возник вопрос! В документации настоятельно не рекомендуют создавать подключение к базе данных в ServerModule, так как это один глобальный ресурс нашего приложения и при многопоточной работе могут возникнуть конфликты, особенно при редактировании данных. Есть конечно вариант занести в критическую зону, но не думаю что это решение для 100 и более подключений.

Поэтому, если я один обращаюсь к этому вэб-сервису, то проблем нет, а если сразу будет 100 подключений? Как это решается, ведь не просто так были созданы процедуры обработки http запросов в ServerModule? Или это сделано только для чтения и для особых случаев, но не для организации вэб сервиса?

Если все таки можно, то подскажите куда двигаться?

Надеюсь понятно изложил мысль?

Link to comment
Share on other sites

Так в том то и вопрос, предназначена ли она для этого. Говорю же, увидел поддержку веб сервисов. А так думаю неплохо было бы в самом унигуи иметь такой сервис и уже ничего стороннего не подключать.

Сейчас нашел delphimvcframework. Разбираюсь. 

А кто чем пользуется? Я так понимаю при каждом запросе должен создаваться отдельный поток с подключением, чтобы не мешать друг другу, чего в ServerModule можно добитсья создавая динамически отдельное соединение, но насколько это оправдано в рамках экономии памяти, не раздует ли сервер при множестве запросов? Ну еще можно с пулом соединения поиграться. В общем у кого какой опыт, поделитесь, направьте пожалуйста.

Link to comment
Share on other sites

6 minutes ago, Kenneth said:

Я так понимаю при каждом запросе должен создаваться отдельный поток с подключением, чтобы не мешать друг другу, чего в ServerModule можно добитсья создавая динамически отдельное соединение

так MainModule для этого предназначен - один MainModule на каждое клиентское подключение

Link to comment
Share on other sites

http запрос не доходит до MainModule, если знаете как его до туда донести, подскажите.

В СерверМодуле есть две прекрасные функции UniGUIServerModuleHTTPCommand и UniGUIServerModuleHTTPDocument, в которых я и принимаю мои запросы, но как до MainModule их донести?

Link to comment
Share on other sites

Для начала надо понять: какому именно экземпляру MainModule нужно переадресовать запрос.

Link to comment
Share on other sites

Можно , обрабатываете события servermodule , датамодуль с бд создаёте в рантайме

Будет медленнее, чем обычный рест

Работать будет

Link to comment
Share on other sites

31 minutes ago, Kenneth said:

http запрос не доходит до MainModule, если знаете как его до туда донести, подскажите.

В СерверМодуле есть две прекрасные функции UniGUIServerModuleHTTPCommand и UniGUIServerModuleHTTPDocument, в которых я и принимаю мои запросы, но как до MainModule их донести?

Передаёте id сессии в запросе, тогда дойдет, но к сервису это не имеет никакого отношения

Link to comment
Share on other sites

Ого сколько мнений! Спасибо за советы! :D

Что то все ушли в сторону МаинМодуля, но по-моему как то это не верно! Задача то по сути следующая:

1. получать http запросы извне;

2. произвести некие действия с базой;

3. вернуть результат.

Вот в принципе и все что надо. МаинМодуль это больше про сессии, которые как бы здесь не особо меня интересуют.

Основное опасение, не будут ли мешать запросы друг-другу, так как СерверМодуль один и коннект один. Тут по-моему есть два варианта:

1. создавать динамически коннект, делать свои дела и уничтожать

2. или создать один коннект с пулом и динамически создавать запросы и уничтожать.

3. или еще ваш вариант....

Будет ли это работать так как надо при больших нагрузках?  Как себя поведет СерверМодуль если одновременно прилетит один и тот же запрос с 10 адресов? Он выполнит их паралельно или же поставит в очередь или же зависнет?

Хотелось бы все таки услышать мнение самих разработчиков или все же смотреть в сторону других решений?

Link to comment
Share on other sites

4 hours ago, stas said:

Можно , обрабатываете события servermodule , датамодуль с бд создаёте в рантайме

Будет медленнее, чем обычный рест

Работать будет

Вы мой ответ читали ?

Link to comment
Share on other sites

@stas прошу прощения, я почему то не так прочитал. даже во второй раз. :o

Да все верно вы написали. А если использовать один коннект с пулом и создавать запросы не будет легче?

Link to comment
Share on other sites

Я думал об этом, но не пришел к определенному выводу, в результате Вы должны создать аналог UniMainModule но без формы.

Оно вам надо?

З.Ы. Пробуйте так, в случае неудачи Вы легко перенесете код на чистый рест (но на indy) 

Link to comment
Share on other sites

Да буду делать тесты, прежде думал спросить, может кто то сталкивался, чтобы не изобретать велосипед. 

Link to comment
Share on other sites

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

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

Создаю в FDManager соединение с пулом, соединения с базой и сами запросы создаю в рантайме, и после уничтажаю их.

Что использовал: Firebird 3.0 + FireDac. На серверМодуль кидаю FDManager, в onCreate настраиваю подключение с пулом и делаю актив=тру. Все как доках. И все!

Дальше принимаю запрос и делаю следующее:

if ARequestInfo.URI = '/test/ins'  then       //запрос на вставку записи
       begin
        Con:=TFDConnection.Create(self);
        con.ConnectionDefName:='FB_Con_srv';
        con.Connected:=true;
        with TFDCommand.Create(self) do
         begin
           Connection:=con;
           CommandText.Add('insert into tbtest(name) values('''+ARequestInfo.Params.Values['n']+''');');
           try
             Execute;
             AResponseInfo.ContentText:='ok';
             AResponseInfo.ResponseNo:=200;
           finally
             free;
             con.Free;
           end;
         end;
         Handled:=true;
       end
       else if ARequestInfo.URI = '/test/get'  then               //запрос на селект
       begin
        Con:=TFDConnection.Create(self);
        con.ConnectionDefName:='FB_Con_srv';
        con.Connected:=true;
        with TFDQuery.Create(self) do
         begin
          Connection:=con;
          SQL.Add('select count(*) as cnt from tbtest;');
          try
            Active:=true;
            AResponseInfo.ContentText:='{"cnt":'+FieldByName('CNT').AsString+'}';
            Close;
          finally
            Free;
            con.Free;
          end;

         end;

Тестил через Stress TestTool. В тесте сначала вставляю запись в табилцу, потом следующей сессией выбираю кол-во записей.

image.png.1aae3cecfd79eb97e5a197b9bef3ee8c.png

250 Сессий отрабатывает на ура, но почему если делать больше, то вылетает с ошибкой. ServerLimits.MaxSession:=1000;

image.png.ade01c8c100979c71bcb12be76f168a0.png

Что еще нужно подкрутить?

Link to comment
Share on other sites

1) Handled в 

  else if ARequestInfo.URI = '/test/get'  then  

2) Что именно Вы тестировали ?

Насколько я вижу Вы тестировали создание пустой формы и приложение благополучно умерло.

Stresstool тут неприменимо, от слова совсем. 

Вам необходимо использовать стандартные тесты рест методов. И на вход подавать полный урл

Link to comment
Share on other sites

@stas

2 hours ago, stas said:

1) Handled в 

код не до конца скопировал, две последние строчки оставил:

 AResponseInfo.ResponseNo:=200;
         Handled:=true;
       end;

Там все нормально.

Теперь на счет тестирования. Согласен напрямую не протестируешь. Поэтому я запустил свой тестовый проект, создал другое приложение, в котором на форме бросил две кнопочки, одна отправляет запрос на мой сервис для вставки записи, другая на селект. Через StressTool запускаю запись сценария, запускается второе приложение, которое обращается к моему целевому, нажимаю последовательно эти две кнопочки, завершаю запись и после прогоняю этот сценарий. При удачном тесте все записи 250 запсей вставляются, что говорит о работе теста. Так что не думаю что СтрессТул неприменим. 

Вопрос остается, почему не получается увеличить кол-во сессий больше 250?

Link to comment
Share on other sites

Вы что хотите протестировать, клиент или сервер ?

Если сервер, то неприменим, если клиент, то вопрос совершенно другой ветки.

Link to comment
Share on other sites

Сервер конечно! А чего не понятного, я же все подробно описал, что я через клиента гружу сервер, в этом и заключается тест. Основная нагрузка на сервер идет, т.к. он за минуту обрабатывает 250 сессий в которых работает с базой! 

Я писал что напрямую через СтрессТул не получиться тестить, поэтому я создал клиента, которого грузит СтрессТул, а тот в свою очередь сервер. Надеюсь понятна мысль?

StressTool -> Client -> Web Server. 

 

Link to comment
Share on other sites

Все вопрос снят. Пока писал ответ, меня осенило :D

Параметр ServerLimits.MaxSession:=1000, был выставлен на целевом сервере, который я тестил, а в промежуточном клиенте стояло 250! Вот он то выводил исключение.

Всем спасибо за советы!

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...