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)

Reply via email to