You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@thrift.apache.org by "Sebastian Zenker (JIRA)" <ji...@apache.org> on 2016/02/01 22:09:39 UTC

[jira] [Commented] (THRIFT-3594) C++: refactor COB style client

    [ https://issues.apache.org/jira/browse/THRIFT-3594?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15127035#comment-15127035 ] 

Sebastian Zenker commented on THRIFT-3594:
------------------------------------------

I don't favor using std::future and co as this would always introduce using threads. If possible, I would like to have the promise fulfilled in the same thread which also issued the rpc call (which requires an eventloop of course). 

> C++: refactor COB style client
> ------------------------------
>
>                 Key: THRIFT-3594
>                 URL: https://issues.apache.org/jira/browse/THRIFT-3594
>             Project: Thrift
>          Issue Type: Wish
>          Components: C++ - Compiler, C++ - Library
>            Reporter: Sebastian Zenker
>
> Let's assume, we have the following thrift interface:
> {code}
> service Calculator
> {
> 	i32 add(1:i32 num1, 2:i32 num2)
> }
> {code}
> When using the COB style code generator, the generated code looks like:
> {code}
> class CalculatorCobClient : virtual public CalculatorCobClIf {
>   ...
>   void add(tcxx::function<void(CalculatorCobClient* client)> cob, const int32_t num1, const int32_t num2);
>   void send_add(const int32_t num1, const int32_t num2);
>   int32_t recv_add();
>   ...
> }
> {code}
> This approach has some drawbacks in my opinion:
> 1.) in case the client is destroyed, that all "open" cob's which have not been processed yet get also destroyed. This could easily lead to a mem- or resource-leak, in case the cob callback needs to release some resources which have been allocated while the request has been sent.
> 2.) in case the cob makes use of an object which has been already destroyed in the meantime -> this may lead to a core dump
> 3.) there is no way to cancel a request
> 4.) there is no way to wait for the completion of a request
> I did take a look into Cap’n Proto's implementation. What they do different on the client side (which is always async), is to return a Promise<T> object for every sent RPC call. As soon as a response is received at the client side, the promise gets fulfilled. If either, the Promise<T> itself of the PromseFulfiller<T> gets destroyed, the Promise get's rejected and a client can react to this situation.
> What do you think about the following generated client implementation?
> {code}
> class CalculatorAsyncClient {
>   ...
>   kj::Promise<int32_t> add(const int32_t num1, const int32_t num2);
>   ...
> }
> {code}
>  
> So a client application my look like:
> {code}
> ...
> kj::WaitScope waitScope;
> ...
> CalculatorAsyncClient client;
> ...
> auto promise = client.add(1, 1);
> // do something else
> int32_t sum = promise.wait(waitScope);
> {code}
> the following would be also possible:
> {code}
> kj::TaskSet ts;
> CalculatorAsyncClient client;
> ...
> ts.add(client.add(1, 1).then([](const int32_t sum)
> {
>   printf("sum = %d\n", sum); // this get's executed when the reponse is received by the client
> }
> ));
> {code}
> What do you think?



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)