GithubHelp home page GithubHelp logo

Comments (36)

lganzzzo avatar lganzzzo commented on May 20, 2024 1

Hello @bkannadassan ,

  1. I am planning to open 1 socket for each request coming in for processing
    in server with the backend and putting it in io read wait.
  2. As explained by you looks like this read socket can't be a timed wait,
    what would be your suggestion on the same ?.
  3. I have one more option is timed wait, but this would delay the response
    even if the response is ready from backend.

Yes, currently there is no custom connection-timeout functionality supported by oatpp.
I am not sure about your use-case or if this is critical for you.
At this point I can't suggest any good workaround as to make it actually work with oatpp-Async API one will need to tweak oatpp-epoll implementation itself.

  1. In client I see that we are using 2 executors, creating curlExecutor and
    another is executor created and used when sending out a client request.
    --> Want to understand if this curlExecutor does create another thread
    ? Would like to understand the purpose of the same.

Please specify what client you are talking about.
If you mean this example project - then curl executor is added here just to show that one can substitute his own request executor as a "backend" for oatpp API Client.

In any case Clients async api calls are executed by coroutine which is run in the executor that you defined. - So no additional threads are populated for client calls.

Regards,
Leonid

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024 1

Hello @bkannadassan ,

Unfortunately there is no good way to do this. In order to do this you'l have to create your own oatpp::async::IOEventExecutor implementation based on epoll.

I can't recommend any solutions at the moment. If something comes to my mind I'll inform you.

Regards,
Leonid

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

One of the possible ways of integrating oatpp with existing application/server and take advantage of oatpp REST controllers (ApiControllers) may look like this:

Create ApiController and Route its Endpoints

  /* Create Router */
  auto router = oatpp::web::server::HttpRouter::createShared();

  /* Create ApiController instance and add its endpoints to Router */
  auto myController = std::make_shared<MyController>();
  myController->addEndpointsToRouter(router);

Handle Custom Requests using oatpp ApiController

  /* Get route and endpoint to handle specified url */
  auto route = router->getRoute("GET", "/hello");

  /* Create Incoming Request with custom parameters */
  auto request = oatpp::web::protocol::http::incoming::Request::createShared(... /* TODO fill in custom params*/); 
  
  /* Call endpoint for request and get response */
  auto response = route.getEndpoint()->handle(request);

  // TODO - process response

Please note: Creating custom request objects is pretty complex task. At the moment there is no convenience API for this purpose.

If you opt to go for this solution, I'll assist you.

Best Regards,
Leonid

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Closing this.
@bkannadassan please reopen if you have more questions on this topic

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

Do you have HTTP parser in your existing application?
If yes, then I would suggest to start with the following:

  • Make sure that you can get the following values from you server for the incoming request:

    • headers
    • body
    • path to endpoint
  • Make sure that your server can send response back with the following values provided:

    • headers
    • body

If you have it all, then the only thing left is to map from your-server request/response to oatpp request/response objects.
For this I'll prepare convenience APIs in order to make it easier.

If you don't have HTTP parser in your application, then you may use oatpp for that.
But in this case I would suggest to consider switching fully to oatpp.

Please Let me know in case of any questions.
I plan to introduce convenience APIs for oatpp request/response construction about next week.

Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

Thanks for letting me know.
So as I understand - you decided to use oatpp without integrating it with your existing libevent server.

Please let me know in case of any other questions.

Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

I was thinking of your case and situation is the following:

  • oatpp could have been easily integrated with your "I/O engine" (libevent) in case you could implement the oatpp::data::stream::OutputStream
    and oatpp::data::stream::InputStream interfaces for your I/O.
    I'm not sure how exactly you work with libevent, but it may be quite difficult to do in case of an event APIs. - This is something that you have to investigate.

  • Just in case if we can't do with http+rest with our libevent, we can
    leverage one of our existing HTTP framework and integrate with oatpp rest
    framework. Please do let us know on the same..

This case looks more straight forward for me. But in this case you'll have to hold all request/response info in the memory which will not suite for ex.: large files upload


Something like this.

Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hey @bkannadassan ,

Yes, in both cases it can work in one thread.

Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

If you have a connection, then pass it directly to ConnectionHandler:

Example:

std::shared_ptr<oatpp::network::server::ConnectionHandler > connectionHandler = <previously created connection handler>;

...

std::shared_ptr<oatpp::data::stream::IOStream> connection = <create connection>;

std::unordered_map<oatpp::String, oatpp::String> parameterMap; // just empty params map
connectionHandler->handleConnection(connection, parametersMap)

You don't need to use Server - it does nothing but gets connection and passes it to connection handler. So if you have your own accept loop - then pass connection directly to ConnectionHandler.

Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

  1. If no large data, then can we reduce the number of IO thread ?.

When using oatpp Async APIs oatpp::async::Executor can be configured to be using the actual number of threads during the construction time.
However when already created it can't change the number of threads.

oatpp::async::Executor executor(
    1 /* data-processing workers */, 
    1 /* I/O workers */, 
    1 /* timer workers */
);

Also when system has no load. All executor workers will be sleeping giving no load to your system.
So there is no much sense in decreasing number of executor threads.

In order to achieve the best performance I usually set such number of threads:

v_int32 cpus = <get number of machine CPUs>
oatpp::async::Executor executor(
          cpus               /* data-processing workers */, 
    0.5 * cpus               /* I/O workers. Should be at least one. */, 
          1                  /* timer workers */
);
  1. If a data received by the server needed to be processed by an
    application should we add our function in the act handler/response handler?

When using oatpp Async APIs all requests processing is delegated to corresponding coroutines
mapped to serve the request.
Method act() of coroutine is the entrypoint for coroutine.

https://github.com/oatpp/oatpp-starter-async/blob/master/src/controller/MyController.hpp#L43

Each method of coroutine should have NON-BLOCKING code only.
In order to wait for some operation (ex.: I/O) - coroutine should "notify" Executor with the proper Action that it should be rescheduled to an I/O or Timer worker.

Example of Async I/O code:
Full example is here

  ENDPOINT_ASYNC("GET", "/body/string", EchoStringBody) {
    
    ENDPOINT_ASYNC_INIT(EchoStringBody)
    
    Action act() override {
      /* return Action to start child coroutine to read body */
      return request->readBodyToStringAsync().callbackTo(&EchoStringBody::returnResponse);
    }
    
    Action returnResponse(const oatpp::String& body){
      /* return Action to return created OutgoingResponse */
      return _return(controller->createResponse(Status::CODE_200, body));
    }
    
  };

Here, the act() method returns the action telling executor to reschedule it on I/O thread, wait until body is full uploaded and then call Action returnResponse(const oatpp::String& body) with the result.

Please note: that oatpp I/O worker uses its own implementation of epoll event loop.

More about oatpp async API read here

  1. Looks like Co-routines start from Data-Processing thread, have some
    doubts here..
    --> Only when there are more data to be received fd is moved to I/O
    processing worker rt ?/
    --> Once execution has done its moved to Timer Processing Workers, I see
    it's moved to Data Processing later. Can you please give more clarity on
    the same ?.
    Current Coroutine calling another Co-routine inside the same can you please
    share on an application ?. Because AFAIK each co-routine registered for a
    specific tag.

"Data Processing" here is everything which is not an I/O or Timer.
Ex.:

  • You prepare data like URLs/ports/IPs etc. - it's data processing.
  • Trying to connect to server (socket connect) - it's I/O
  • Management of the "ready" socket like - put it in the map, or array or whatever you do with the FD - is data processing.
  • You call "read" on the socket - it's I/O

So on each step coroutine gets rescheduled.

Timer worker is not used for I/O at all. It is used to wait for some time only. Ex.: when you need to schedule some operation to happen by timer.

// Current Coroutine calling another Co-routine inside the same can you please
share on an application ?

See the example:

    Action act() override {
      /* return Action to start child coroutine to read body */
      return request->readBodyToStringAsync().callbackTo(&EchoStringBody::returnResponse);
    }
    
    Action returnResponse(const oatpp::String& body){
      /* return Action to return created OutgoingResponse */
      return _return(controller->createResponse(Status::CODE_200, body));
    }

Here coroutine calls another coroutine request->readBodyToStringAsync() to read body and store it to string.

  1. Please note we are looking this interface to integrate for
    1) Sending consul query to consul server {Have Seen A Sample
    Implementation and would try to leverage the same}
    2) Use Rest Interface to send Query to different tasks and receive a
    response from the same.
    We are looking to implement watch rest api similar to " curl -G
    http://127.0.0.1:8500/v1/kv/lead?index=<mod-index#>&wait=10s " , this
    would wait for a response from consul server. I hope this shouldn't be an
    issue with the framework.
    --> Do you see any issues in doing the same ?.

In order to get KV from Consul in Async manner you may use oatpp::consul rest client.
https://github.com/oatpp/oatpp-consul/blob/master/src/oatpp-consul/rest/Client.hpp#L69

// We are looking to implement watch rest api similar to " curl -G http://127.0.0.1:8500/v1/kv/lead?index=<mod-index#>&wait=10s "

As far as I know (and can be seen from Consul API docs https://www.consul.io/api/kv.html) there is no &wait=10s parameter in Consul KV API.

However for wait fot 10s you can easily implement manually.

Additional Info:
Btw I have written with server implementation having both handler and
provider inside the same, but
addConn function takes fd and performs this task.
I have forked and created one in github under example-async.

I can see that you go with oatpp async API and you are trying to reuse oatpp::async::Connection.

Please note that for async model oatpp::async::Connection will suggest the async executor to reschedule coroutine(which is using this connection) to the I/O worker. And I/O worker is designed to uses oatpp implementation of epoll.

At this point I can see that integrating you own libevent server with oatpp Async will be hard.
I suggest to go with oatpp blocking model (simple multithreaded API). - This will make integration much easier.

So that integration will look like this:

In this case you may use oatpp REST framework with simple APIs.

Btw you were saying about " Creating custom request objects is a pretty
complex task. At the moment there is no convenience API for this purpose.
", please let us know the timeline on the same since we might need the
same. I am planning to use ppconsul over this if possible so that ppconsul
will be framing the query to consul server.

This is planned for the nearest release.
By the end of July or by beginning of August.

Best Regards,
Leonid

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

Please find the project I've built for you - https://github.com/lganzzzo/oatpp-integration-example

This is an example of the possible way to integrate your project with oatpp REST framework.

Integration on "lower" level seems to be too complicated at the moment.

Best Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

Please do not make router static. Place it in config - as in the example project.

You can add you Controllers endpoints to router like as shown in the example:
https://github.com/lganzzzo/oatpp-integration-example/blob/master/src/App.cpp#L28

  /* Get router component */
  OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);

  /* Create MyController and add all of its endpoints to router */
  auto myController = std::make_shared<MyController>();
  myController->addEndpointsToRouter(router);

Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hey @bkannadassan ,

If you are using oatpp Async API (as I can guess) with AsyncExecutor then it is required to have at least one IO worker. And Each IO worker will populate two threads - two threads is required to be able to work in the full duplex mode.

Currently the only way to have no threads populated during the request processing in oatpp - is to implement integration as shown in the example project that I've built for you.

Regards,
Leonid

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Uh, you fixed that:)
Ok, thanks for letting me know.

Please let me know in case you have more questions.

Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

Seems like you wanted to attache some image to your comment but image is not attached.

If I understand correctly, you have the following situation:

  • You have no threads on your system by some reason (I didn't get if its hardware issue or because of your design).
  • You already use libevent to receive I/O events and accept connections.
  • You process each batch of events in the same thread. (he same thread that you run your event-loop in)

If it so,- then the best way for you to integrate with oatpp - is like in the example that I've created for you. In this case you will have no threads populated.
The flow is as follows:
(New Connection) --> (Libevent Accept) --> (Your HTTP parser) --> (Create oatpp Request Object from parsed values) --> (oatpp process request)
And when you have a response object from oatpp you do:
(oatpp process request) --> (obtain response object) --> (oatpp render response to buffer) --> (Your I/O processor Send buffer back to client)


In case of Async oatpp you will have to allocate min 5 threads:

  • 1 accepting thread.
  • 1 Data processing thread
  • 2 I/O threads
  • 1 Timer thread

With this number of threads you may then process whatever number of parallel connections you have.

But in this case the only thing that you can change is the acceptor. All other I/O will be handled by oatpp.


Please let me know if I misinterpreted something or in case you have more questions.

Best Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

I'll be able to reply later on Friday (EET).

Sorry for inconvenience.

Best Regards,
Leonid

from oatpp.

lganzzzo avatar lganzzzo commented on May 20, 2024

Hello @bkannadassan ,

Please use Github UI for commenting, and please use markdown code snippets.
See markdown cheatsheet for more info.

Because it is very hard to read unformatted code commented in email.


Coming back to your questions:

  1. I want to have this timeout in reading how to have wait for read with a
    timeout ?.

Unfortunately timeout is not currently supported for coroutine actions of type TYPE_IO_WAIT , TYPE_IO_REPEAT

  1. I think this response which I am putting in the buffer should be put in
    a request so that it can be propagated into the subsequent co-routine. How
    can this be done ?.

To obtain http response from other service in Async manner use oatpp ApiClient.
In this case your code will look something like this:

class HttpGetCoroutine : public oatpp::async::Coroutine<HttpGetCoroutine> {
private:
  OATPP_COMPONENT(std::shared_ptr<app::Client>, appClient); // Your oatpp API client with "httpGetAsync" method defined as "API_CALL_ASYNC"
public:

  Action act() override {
    return appClient->httpGetAsync().callbackTo(&HttpGetCoroutine::onResponse);
  }

  Action onResponse(const std::shared_ptr<IncomingResponse>& response) {
    return response->readBodyToStringAsync().callbackTo(&HttpGetCoroutine::onBodyRead);
  }

  Action onBodyRead(const oatpp::String& body) {
    OATPP_LOGD("HttpGetCoroutine", "body='%s'", body->getData());
    return finish();
  }

};

Best Regards,
Leonid

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

from oatpp.

bkannadassan avatar bkannadassan commented on May 20, 2024

Hi Leonid,

I am planning to start a co-routine to periodically run for every 10secs and check if there are any request pending for IO event for > 10sec and cleanup them. I can start the co-routine for this and trigger the same, but I am not sure how to get the list of pending request and find those > 10 secs, Can you provide some pointers on the same? or is it not possible to do the same ?.

rgds
Balaji Kamal Kannadassan

from oatpp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.