Thread: [Cppcms-users] Mounting both synchronous and asynchronous applications
Brought to you by:
artyom-beilis
From: CN <cn...@gr...> - 2011-02-01 04:26:35
|
Hello, Imagine my site has both synchronous (for user login) and asynchronous (for interactive activities) pages. Is it a correct and good practice to mount both synchronous and asynchronous applications like the following code? //code begin class login:public cppcms::application{ .... } class interaction:public cppcms::application{ .... } int main() { cppcms::service s(argc,argv); s.applications_pool().mount(cppcms::applications_factory<login>()); booster::intrusive_ptr<interaction> i=new interaction(s); s.applications_pool().mount(i); s.run(); } //code end Please also correct me if my following thoughts are wrong: - When a request arrives, cppcms::service.run() loops all mounted applications and pass that request to every mounted application. It is the responsibility of every application to filter the interested passed in request by applying dispatcher().assign(). - This program can fire multiple instances of "login" class. Every login instance runs as a separate thread. Thus this program can concurrently process multiple incoming synchronous (login) requests. - This program process asynchronous requests only one at a time because only one instance of class "interaction" is created. As such, asynchronous applications are most likely the bottleneck of performance when the load is heavier. Thank you in advance! CN |
From: Artyom <art...@ya...> - 2011-02-01 06:08:36
|
> From: CN <cn...@gr...> > Hello, > > Imagine my site has both synchronous (for user login) and asynchronous > (for interactive activities) pages. Is it a correct and good practice to > mount both synchronous and asynchronous applications like the following > code? > > //code begin > class login:public cppcms::application{ .... } > class interaction:public cppcms::application{ .... } > > int main() > { > cppcms::service s(argc,argv); > > s.applications_pool().mount(cppcms::applications_factory<login>()); > > booster::intrusive_ptr<interaction> i=new interaction(s); > s.applications_pool().mount(i); > > s.run(); > } > //code end > Yes and not, you should provide a mount point that would distinguish between them: See: - http://art-blog.no-ip.info/cppcms_ref_v0_99/classcppcms_1_1applications__pool.html - http://art-blog.no-ip.info/cppcms_ref_v0_99/classcppcms_1_1mount__point.html > Please also correct me if my following thoughts are wrong: > > - When a request arrives, cppcms::service.run() loops all mounted > applications and pass that request to every mounted application. It is the > responsibility of every application to filter the interested passed in > request by applying dispatcher().assign(). > Not it would pass the request to the first application that matches the mount point pattern. And it would not it to only one such application. Note it is multi-layered search: If there is no specific patch assigned to dispatcher it would return error 404 (unless you had redefined application::main and do not use dispatcher > - This program can fire multiple instances of "login" class. Every login > instance runs as a separate thread. Thus this program can concurrently > process multiple incoming synchronous (login) requests. > Yes and No. A pool of synchronous applications is created. At each request once instance is taken from the applications pool and passed to thread pool for execution. Once it completes it is recycled for reuse in the pool. So multiple instances run synchronously concurrently. > - This program process asynchronous requests only one at a time because > only one instance of class "interaction" is created. > No, asynchronous application is executed in main event loop, when new request is ready it is passed to the application, unlike the case of synchronous application it can detach the http::context object and "keep" it for further response (to provide long polling). and then get more requests. So basically asynchronous application can handle multiple request and this is needed mostly for server side events and long polling. See examples/chat > As such, asynchronous > applications are most likely the bottleneck of performance when the load > is heavier. If you do heavy processing there then yes, but you should not. You are expected to do very lightweight operations there if you have heavy processing either use synchronous application and notify the asynchronous one passing it the results. Or use the CppCMS's thread pool to handle heavy operations. Don't forget that you can't access asynchronous app. directly from other threads you rather need to use cppcms::service::post to pass the handler to the main event loop for execution to ensure thread safety. Basically: - When you need COMET/Server side events use asynchronous app, - Otherwise use synchronous one. Artyom |
From: CN <cn...@gr...> - 2011-02-01 15:29:47
|
Many thanks for the quick help! > you should provide a mount point > that would distinguish between them: > > See: > > - > http://art-blog.no-ip.info/cppcms_ref_v0_99/classcppcms_1_1applications__pool.html > > - > http://art-blog.no-ip.info/cppcms_ref_v0_99/classcppcms_1_1mount__point.html > Now I am trying to also provide mount() parameter mount_point but have trouble with the matching: //code begin class sync_app:public cppcms::application{ .... } class async_app:public cppcms::application { async_app(cppcms::service &srv) : cppcms::application(srv) { dispatcher().assign("(.*)",&async_app::catch_all,this,1); } void catch_all(std::string url) { BOOSTER_LOG(debug,"URL") << url; } } int main(int argc,char **argv) { cppcms::service s(argc,argv); s.applications_pool().mount(cppcms::applications_factory<sync_app>(),cppcms::mount_point("/s/a")); booster::intrusive_ptr<async_app> as_app=new interaction(s); //Watch the match string in the next line! s.applications_pool().mount(as_app,cppcms::mount_point("/as/a")); s.run(); } //code end Browser accesses to URL "/as/a". The match strings and logs follows: match string log --------------- /as (none) .* /as/a as (none) a (none) /a (none) /as/a (none) That being said, only provided with script ".*" will mount_point() fire application "async_app": s.applications_pool().mount(i,cppcms::mount_point(".*")); Any idea what mistake I have made? Regards, CN |
From: Artyom <art...@ya...> - 2011-02-01 15:52:23
|
> > - > > http://art-blog.no-ip.info/cppcms_ref_v0_99/classcppcms_1_1mount__point.html > > > > Now I am trying to also provide mount() parameter mount_point but have > trouble with the matching: First of all read once again this: http://art-blog.no-ip.info/cppcms_ref_v0_99/classcppcms_1_1mount__point.html Most likely you are looking for: http://art-blog.no-ip.info/cppcms_ref_v0_99/classcppcms_1_1mount__point.html#8aed02e81a2442db463910d47ac8d27a Basically you are probably looking for s.applications_pool().mount(cppcms::applications_factory<sync_app>(), cppcms::mount_point("/s/(.*)",1)); s.applications_pool().mount(as_app, cppcms::mount_point("/as/(.*)",1)); When you mount with one parameter you are using SCRIPT_NAME variable and PATH_INFO passed to the main(url) When you mount with string parameter and integer parameter you are using PATH_INFO and match against url and then pass matched part to main I don't know what is your web server configuration (or script names) so I can't tell you what happens, best is to match against PATH_INFO Artyom |
From: CN <cn...@gr...> - 2011-02-01 15:47:06
|
My brain starts to malfunction due to late hour here. Sorry for the previous incorrect code. Please use this one instead. The unexpected results mentioned in last post remain unresolved. //code begin class sync_app:public cppcms::application{ .... } class async_app:public cppcms::application { async_app(cppcms::service &srv) : cppcms::application(srv) { dispatcher().assign("(.*)",&async_app::catch_all,this,1); } void catch_all(std::string url) { BOOSTER_LOG(debug,"URL") << url; } } int main(int argc,char **argv) { cppcms::service s(argc,argv); s.applications_pool().mount(cppcms::applications_factory<sync_app>(),cppcms::mount_point("/s/a")); booster::intrusive_ptr<async_app> as_app=new async_app(s); //typo error //Watch the match string in the next line! s.applications_pool().mount(as_app,cppcms::mount_point("/as/a")); s.run(); } //code end Browser accesses to URL "/as/a". The match strings and logs follows: match string log --------------- /as (none) .* /as/a as (none) a (none) /a (none) /as/a (none) That being said, only provided with script ".*" will mount_point() fire application "async_app": s.applications_pool().mount(as_app,cppcms::mount_point(".*")); Regards, CN |
From: CN <cn...@gr...> - 2011-02-02 04:01:02
|
This morning this program all a sudden begins to match requested URI. The possible reason for being not working last night most likely is because the browser did not fully reload java script and/or the web page from web server (because of its caching mechanism?) even I clicked its refresh button. I had this experience before and wasted hours looking for the cause of unexpected behavior. If people start to get the similar weird result, please try closing the tab from your browsers and then locate the URI again, or even restart it. Back to my point... I am able to proceed my work now. However, there is still one thing I don't understand: class async_app : public cppcms::application { public: async_app(cppcms::service &srv) : cppcms::application(srv) { dispatcher().assign("^ps$",&async_app::catch_all,this); } void catch_all() { BOOSTER_LOG(debug,"async app is fired"); std::map<std::string,std::string> env=request().getenv(); std::map<std::string,std::string>::const_iterator i; for(i=env.begin();i != env.end();++i) BOOSTER_LOG(debug,"ENV") << (*i).first << ":" << (*i).second; } } int main(int argc,char **argv) { cppcms::service s(argc,argv); s.applications_pool().mount(cppcms::applications_factory<sync_app>(),cppcms::mount_point("/s/(.*)",1)); booster::intrusive_ptr<async_app> e=new async_app(s); s.applications_pool().mount(e,cppcms::mount_point("/as/(.*)",1)); s.run(); return 0; } The excerpted log follows: 2011-02-02 02:30:07 GMT; ENV, debug: DOCUMENT_ROOT:/var/www/example (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: GATEWAY_INTERFACE:CGI/1.1 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_ACCEPT:text/html, */* (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_ACCEPT_CHARSET:iso-8859-1, utf-8, utf-16, *;q=0.1 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_ACCEPT_ENCODING:deflate, gzip, x-gzip, identity, *;q=0 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_CONNECTION:Keep-Alive, TE (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_HOST:www.example.com (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_REFERER:http://www.example.com/test.html (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_TE:deflate, gzip, chunked, identity, trailers (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_USER_AGENT:Opera/9.80 (X11; Linux i686; U; en) Presto/2.7.62 Version/11.00 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: HTTP_X_REQUESTED_WITH:XMLHttpRequest (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: PATH_INFO:/as/ps (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: PATH_TRANSLATED:/var/www/example/as/ps (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: QUERY_STRING: (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: REDIRECT_STATUS:200 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: REMOTE_ADDR:127.0.0.1 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: REMOTE_PORT:41362 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: REQUEST_METHOD:GET (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: REQUEST_URI:/cgi/as/ps (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: SCRIPT_FILENAME:/var/www/example/cgi (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: SCRIPT_NAME:/cgi (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: SERVER_ADDR:127.0.0.1 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: SERVER_NAME:www.example.com (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: SERVER_PORT:80 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: SERVER_PROTOCOL:HTTP/1.1 (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: SERVER_SOFTWARE:lighttpd/1.4.28-devel-485M (cgi.cpp:114) Please take special note of these two lines in the log: 2011-02-02 02:30:07 GMT; ENV, debug: PATH_INFO:/as/ps (cgi.cpp:114) 2011-02-02 02:30:07 GMT; ENV, debug: SCRIPT_NAME:/cgi (cgi.cpp:114) The description for the overloaded function cppcms::mount_point::mount_point(std::string const &script) is "Create a mount point that checks SCRIPT_NAME, and passes PATH_INFO for dispatching the version of mount_point() among the overloads" Refer to: http://cppcms.sourceforge.net/cppcms_ref_v0_99/classcppcms_1_1mount__point.html My understanding is that the following code should match nothing: s.applications_pool().mount(e,cppcms::mount_point("/as/(.*)",1)); because according to the log, the incoming SCRIPT_NAME is "/cgi". However, the reality is that it matches! On the contrary, this version fails to match: s.applications_pool().mount(e,cppcms::mount_point("/cgi/(.*)",1)); Is this a descrepancy between CppCMS documentation and the library itself? Best Regards, CN |
From: Artyom <art...@ya...> - 2011-02-02 08:59:30
|
> > Back to my point... I am able to proceed my work now. However, there is > still one thing I don't understand: > > { > dispatcher().assign("^ps$",&async_app::catch_all,this); > } > >s.applications_pool().mount(cppcms::applications_factory<sync_app>(),cppcms::mount_point("/s/(.*)",1)); > > s.applications_pool().mount(e,cppcms::mount_point("/as/(.*)",1)); Lets start: Quoting Documentation: > cppcms::mount_point::mount_point(std::string const & path,int group) > > Create a mount point that checks PATH_INFO only and passes matched group for >dispatching > That means that PATH_INFO is matched so PATH_INFO = /as/ps Matched agains: /as/(.*) And then "ps" is selected and passed to main of application that on "^ps$" gets matched. What does not match the documentation? > cppcms::mount_point::mount_point(std::string const &script) > > Create a mount point that checks SCRIPT_NAME, and passes PATH_INFO for >dispatching > Now this is fo case where we have for exaple foo.cgi bar.cgi And you want to match them So for URL foo.cgi/beep SCRIPT_NAME=foo.cgi PATH_INFO=/beep foo.cgi would be matched by mount_point("foo.cgi") and then "/beep" would passed to main of the application for dispatching ... > cppcms::mount_point::mount_point() > > Create default mount point, it uses PATH_INFO for url-dispatching and gives no >restriction on URL > This case - the default mount point when you use just a one application it passes all PATH_INFO for URL dispatching. > Please take special note of these two lines in the log: > > 2011-02-02 02:30:07 GMT; ENV, debug: PATH_INFO:/as/ps (cgi.cpp:114) > 2011-02-02 02:30:07 GMT; ENV, debug: SCRIPT_NAME:/cgi (cgi.cpp:114) > > The description for the overloaded function > > cppcms::mount_point::mount_point(std::string const &script) > > is > > "Create a mount point that checks SCRIPT_NAME, and passes PATH_INFO for > dispatching the version of mount_point() among the overloads" > > Refer to: > > http://cppcms.sourceforge.net/cppcms_ref_v0_99/classcppcms_1_1mount__point.html > > My understanding is that the following code should match nothing: > > s.applications_pool().mount(e,cppcms::mount_point("/as/(.*)",1)); > No. It is matched against PATH_INFO that is the usual case > because according to the log, the incoming SCRIPT_NAME is "/cgi". However, > the reality is that it matches! On the contrary, this version fails to > match: > > s.applications_pool().mount(e,cppcms::mount_point("/cgi/(.*)",1)); > > Is this a descrepancy between CppCMS documentation and the library itself? No, you just should read documentation more carefully. Different mount points constructors have different semantics allowing to both use script_name and path_info for dispatching, however every mount point should extract something to pass to application's main. Artyom |
From: CN <cn...@gr...> - 2011-02-02 16:09:35
|
Indeed, I appeared to be comparing apples and oranges. Perhaps it's time for me to take some rest before I proceed. Thank you for your time! Regards, CN |