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:06:39 UTC

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

Sebastian Zenker created THRIFT-3594:
----------------------------------------

             Summary: 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)