AutobahnCpp async RPC

57 views
Skip to first unread message

Rosa Lisin

unread,
Mar 31, 2015, 10:31:58 AM3/31/15
to autob...@googlegroups.com
Hi Tobias,
I have another question regarding RPCs that can take some time to execute (DB procedure for example). It would be nice to implement those kind of RPCs as asynchronous, so that the calee would not be stuck executing a single RPC. It looks like theer is a way to register async RPC (provide_f, provide_fm, etc).  But there seem to be no way to call the RPC registered this way. It seems to me that there must be call_f call_fm, etc corresponding methods. Please confirm that my understanding is correct.

Thanks,
Rosa
  

Tobias Oberstein

unread,
Mar 31, 2015, 11:15:04 AM3/31/15
to autob...@googlegroups.com
Am 31.03.2015 um 16:31 schrieb Rosa Lisin:
> Hi Tobias,
> I have another question regarding RPCs that can take some time to
> execute (DB procedure for example). It would be nice to implement those
> kind of RPCs as asynchronous, so that the calee would not be stuck
> executing a single RPC. It looks like theer is a way to register async

Yes. And you don't need shared registrations for that. What you want is
an _asynchronous database client library_ that integrates with the event
loop (Boost/ASIO).

The problem is: most database client libraries are blocking (not async).

E.g. the Oracle database client library is blocking by nature.
PostgreSQL is also blocking by default (though it has a feature that
allows for async).

The way this is usually solved (e.g. in Twisted's database support) is
by executing database stuff on a background worker thread pool.

In pseudocode:

Future f = db.run_query("select count(*) from mytab");

Under the hood, it'll run the query on a background thread, and when the
result comes back, wake up the Future f.

In AutobahnCpp you could use that for implementing a procedure
("provide" .. since "register" is a C++ keyword) and simply return the
future as a result.

> RPC (provide_f, provide_fm, etc). But there seem to be no way to call
> the RPC registered this way. It seems to me that there must be call_f
> call_fm, etc corresponding methods. Please confirm that my understanding

Not sure what you mean .. you can "provide" a function to be callable
from a remote client. A function "provided" in that way is _also_
callable from within the same client that provides the function. In this
case, the call will travel to the router and come back again (if there
is no shared registration).

You cannot magically make a database client library non-blocking by any
combination of "provide"/"call".

If your C++ program runs on a single thread, and you make that thread
enter a blocking database client library, that thread will be blocked
until the DB lib comes back. No WAMP stuff will be processed in the
meantime, and your client will appear being non-responsive from the
router perspective.

You can use shared registrations to work around the blocking nature of
DB libs, but that's not what shared registrations are really intended
for. Since if you do that, your (single-threaded) WAMP component will
look unresponsive from outside (to the router), and the router e.g.
won't be able to interrupt a call into your component (since the code
therein is "busy" sitting and waiting for the DB to return).

To work around blocking DB libs in an asynch context, the usual pattern
is to not block the main thread running the event loop and execute any
blocking stuff on a background thread pool.

nodejs works like this. Twisted and asyncio work like this.

Also: do you really need to do the DB access from C++?

You could encapsulate DB access in a WAMP component written in a more
friendly language (better: a language that has already solved blocking
DB libs and async). And then just call into the former component from
your C++ component.

WAMP is about making an app out of decoupled components - potentially
written in multiple languages. Having "data access" separated into a
component used by other sounds fine for me. And you can use the polyglot
power of WAMP here .. don't bother with C++ heavy artillery if you don't
have to;)

===

Contrast:

async programming is great if your code would otherwise just sit and
wait (like for I/O).

If you run CPU intensive stuff, your code is actually doing useful work
(not just waiting). And this is where shared registrations come in.

Hopefully I am not triggering more questsions than answering ones;)

Cheers,
/Tobias


> is correct.
>
> Thanks,
> Rosa
>
> --
> You received this message because you are subscribed to the Google
> Groups "Autobahn" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to autobahnws+...@googlegroups.com
> <mailto:autobahnws+...@googlegroups.com>.
> To post to this group, send email to autob...@googlegroups.com
> <mailto:autob...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/autobahnws/8af04765-ed53-4c96-87a6-ef2a621e3931%40googlegroups.com
> <https://groups.google.com/d/msgid/autobahnws/8af04765-ed53-4c96-87a6-ef2a621e3931%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.

Rosa Lisin

unread,
Mar 31, 2015, 11:56:47 AM3/31/15
to autob...@googlegroups.com
Hi Tobias,
I actually used DB call as an example, and it turned out to be not a good one. I realize C++ is not the best choise when dealing with DB.
Suppose the Remote Procedure has to establish connection with some network endpoint, so most of the time the RP will do nothing but wait for response. So the natural way to go, it seems, is to use an async remote procedure.

But when I tried to run a simple test registering function by calee:

future<any> my_func (const anyvec& myvec, const anymap& mymap) {
             return boost::async(boost::bind(do_something,args,kwargs));
}
.......
session.provide_f("com.myapp.cpp.my_func", &my_func );
........

But when the caller actually calls it:
session.call("com.myapp.cpp.my_func", somevec,somemap);

The calee experiences the following error:
FIX ME INVOCATION 
St8functionIFN5boost3anyERKSt6vectorIS1_SaIS1_EERKSt3mapISsS1_St4lessISsESaISt4pairIKSsS1_EEEEE
St8functionIFN5boost6futureINS0_3anyEEERKSt6vectorIS2_SaIS2_EERKSt3mapISsS2_St4lessISsESaISt4pairIKSsS2_EEEEE

Am I doing something wrong? 

Thanks,
Rosa
Reply all
Reply to author
Forward
0 new messages