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

Adam Hawkins commented on THRIFT-2908:
--------------------------------------

Thanks for the quick response. I've prepared some small code examples to make 
sure you and I are communicating correctly. Here's an example Thrift IDL file.

{code:title=echo_service.thrift}
service EchoService {
  string echo(1: string message)
  void explode()
}
{code}

Here's a snippet from the generated {{echo_service.thrift}} file.

{code:title=echo_service.rb}
class Processor
  include ::Thrift::Processor

  def process_echo(seqid, iprot, oprot)
    args = read_args(iprot, Echo_args)
    result = Echo_result.new()
    result.success = @handler.echo(args.message)
    write_result(result, oprot, 'echo', seqid)
  end

  def process_explode(seqid, iprot, oprot)
    args = read_args(iprot, Explode_args)
    result = Explode_result.new()
    @handler.explode()
    write_result(result, oprot, 'explode', seqid)
  end
end
{code}

There is no exception handling there. Now if I modify the IDL to throw an 
exception like so:

{code:thrift}
exception EchoException { }
service EchoService {
  string echo(1: string message)
    throws (1: EchoException noEcho)
  void explode()
}
{code}

The resulting processor code now includes appropriate {{rescue}} clauses based 
off the IDL.

{code:ruby}
class Processor
  include ::Thrift::Processor

  def process_echo(seqid, iprot, oprot)
    args = read_args(iprot, Echo_args)
    result = Echo_result.new()
    begin
      result.success = @handler.echo(args.message)
    rescue ::EchoException => noEcho
      result.noEcho = noEcho
    end
    write_result(result, oprot, 'echo', seqid)
  end

  def process_explode(seqid, iprot, oprot)
    args = read_args(iprot, Explode_args)
    result = Explode_result.new()
    @handler.explode()
    write_result(result, oprot, 'explode', seqid)
  end

end
{code}

This is where my confusion begins and hopefully we can clear that up. Now it's 
time to implement this {{EchoService}} in ruby. An example handler would be:

{code:ruby}
class Handler
  def echo(string)
    string
  end
end
{code}

This this is a correct implementation and will behave correctly with the thrift 
servers in the ruby library. Now if the {{Handler}} class is implemented 
incorrectly like so:

{code:ruby}
class Handler
  def echo(string)
    nil
  end
end
{code}

The client would raise/throw a {{TApplicationException}} because the server did 
not return the correct type ({{NilClass}} instead of a {{String}}). This is the 
correct and expected behavior based on my reading. Now if we change the handler 
to fail in a different way.

{code:ruby}
class Handler
  def echo(string)
    fail "Unexpected error!"
  end
end
{code}

If a client calls the {{echo}} RPC the server will fail in different ways. 
Using the thread pool server, the thread handling that RPC dies and exits. The 
client receives a {{TTransportException}} and if uncaught the process exits. 
It's my understanding that we should be able to wrap all the service handlers 
in something like:

{code:ruby}
class Handler
  def echo(string)
    # do something
  rescue => ex
    raise Thrift::ApplicationException.new(Thrift::Application::INTERNAL_ERROR, 
ex.to_s)
  end
end
{code}

Then the thrift library can communicate that failure to the clients and they'll 
receive a {{TApplicationException}} and react accordingly. However this is not 
currently the case. Throwing the {{Thrift::ApplicationException}} or returning 
it has no impact on what the client receives, it receives a 
{{TTransportException}} in both cases. Is this the correct behavior or should I 
be able to wrap my calls to catch exceptions and forward them as 
{{TApplicationException}} to clients?

> Limited use Thrift::ApplicationException in Ruby
> ------------------------------------------------
>
>                 Key: THRIFT-2908
>                 URL: https://issues.apache.org/jira/browse/THRIFT-2908
>             Project: Thrift
>          Issue Type: Bug
>          Components: Ruby - Library
>    Affects Versions: 0.9.2
>            Reporter: Adam Hawkins
>
> I'm implementing a bunch of Thrift servers in Ruby. I'm trying to figure out 
> how to use {{Thrift::ApplicationException}} for error handling. I came across 
> a link on stack overflow 
> [http://stackoverflow.com/questions/27312244/general-error-handling-in-apache-thrift]
>  that documents exactly what I'm trying to do but applied to the delphi 
> library. The fix (THRIFT-2860) has been merged and set for 0.9.3 release. I'm 
> investigating the generated ruby code and it seems 
> {{Thrift::ApplicationException}} is only used in the clients, and never 
> mentioned in any of the server or processor code. Is it possible to implement 
> a similar fix for ruby severs, or should I define a generic exception and 
> have all RPC's throw that as a work around?



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

Reply via email to