You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@thrift.apache.org by Craig Artley <ca...@hotmail.com> on 2012/05/11 01:06:20 UTC

Using TApplicationException - need example

Hello, I want to take exceptions on the server and return them back to the client. For example, say the client's request leads to a run time exception like IllegalArgumentException. I think that TApplicationException with INTERNAL_ERROR is the way to do this, but I couldn't get it to work and I can't find any examples.

In my service handler, I check the args.  If they are invalid, I threw a TApplicationException like this
  throw new TApplicationException(TApplicationException.INTERNAL_ERROR,"Illegal argument blah blah");

It still showed up in my client as a TTransportException:
org.apache.thrift.transport.TTransportException
    at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132)

I'm sure I am just misunderstanding something.  What am I missing? Can anyone provide an example of robust exception handling in the server to the client?

I read about it in THRIFT-378
https://issues.apache.org/jira/browse/THRIFT-378

Regards,
  -craig
 		 	   		  

Re: Using TApplicationException - need example

Posted by Rush Manbert <ru...@manbert.com>.
Hi Craig,

You're welcome.

I looked into our generated code. I have a test for a database server. It uses our custom exception, but I think that just added an extra catch. If I set a breakpoint in my server implementation code, then look back down the stack frames, I find this:

  try {
    iface_->commitDatabaseChangesAndUnlock(result.success, args.commitStore, args.lockHandle); <-- My server function
    result.__isset.success = true;
  } catch (OurThriftExceptionWire &ex) {
    result.ex = ex;
    result.__isset.ex = true;
  } catch (const std::exception& e) {
    ::apache::thrift::TApplicationException x(e.what());
    oprot->writeMessageBegin("commitDatabaseChangesAndUnlock", ::apache::thrift::protocol::T_EXCEPTION, seqid);
    x.write(oprot);
    oprot->writeMessageEnd();
    oprot->getTransport()->flush();
    oprot->getTransport()->writeEnd();
    return;
  }

so it looks like C++ server code does catch any std::exception and throw TApplicationException across the wire, with the what() from the original exception.

On the client side, I have something similar:
void MyClient::recv_commitDatabaseChangesAndKeepLock(std::vector<LsDoubleRelation> & _return)
{

  int32_t rseqid = 0;
  std::string fname;
  ::apache::thrift::protocol::TMessageType mtype;

  iprot_->readMessageBegin(fname, mtype, rseqid);
  if (mtype == ::apache::thrift::protocol::T_EXCEPTION) {
    ::apache::thrift::TApplicationException x;
    x.read(iprot_);
    iprot_->readMessageEnd();
    iprot_->getTransport()->readEnd();
    throw x;
  }
// The rest of the function is elided...

so on the client side it looks for a message type T_EXCEPTION. If it finds one, then it generates and throws a TApplicationException.

Now, what I don't quite get is that I thought I read some code earlier today that was detecting T_EXCEPTION, but was throwing TTransportException on the client side. But now I can't find that in our generated code.

- Rush

On May 17, 2012, at 5:21 PM, Craig Artley wrote:

> 
> Rush, thanks for the reply and the example code. I got that working with Java server and clients without too much drama.
> 
> Still, when I read the THRIFT-378 (https://issues.apache.org/jira/browse/THRIFT-378) I get the feeling that it should not be this tedious. Quoting from the original description:
> 
> ---
> One workaround might be to add an InternalError exception and declare
> every method to throw that, but this would require wrapping each method
> implementation on the server with a try/catch/throw block, which is 
> ugly and repetitive (especially if there are other try/catch blocks 
> nested) – exactly the sort of code that Thrift is good at automating 
> away.
> 
> 
> I think the right fix would be for the server to catch runtime 
> exceptions in the generated process methods and send back a 
> TApplicationException.  This is what some other servers (e.g., Erlang) 
> already do.---
> 
> So what we have done is essentially implement the "workaround": boilerplate code in every method to explicitly catch internal problems and throw a custom exception.
> 
> The original reporter really nailed in the last sentence - server should automatically catch run time exceptions and throw TApplicationExceptions to the client. The bug is marked as resolved for nearly 3 years, so I must be completely misunderstanding the intent.  Isn't it supposed to automatically toss back to the client a TApplicationException of type INTERNAL_ERROR? Do I really have to do that by hand in every single method? Do people have to do that with C++ servers too, or is this only a problem with Java servers?
> 
> It was supposedly fixed, but maybe I just don't understand the goal. When my sever hits a run time exception, the client just gets a cryptic TTransportException with no clue of what went wrong.
> 
> Regards,
>   -craig
> 
> ----------------------------------------
>> Subject: Re: Using TApplicationException - need example
>> From: rush@manbert.com
>> Date: Thu, 17 May 2012 09:44:30 -0700
>> To: user@thrift.apache.org
>> 
>> 
>> On May 16, 2012, at 10:07 PM, Steve Angelovich wrote:
>> 
>>> What is TApplicationException intended to be used for?
>>> 
>>> Is there a mechanism in thrift to propagate a runtime exception from the server back to the client?
>>> 
>>> How do others deal with a case where the caller has made an RPC call with an invalid argument. In Java I'd normally throw a IllegalArgumentException, is something like this possible in thrift or do I have to add another user defined exception type which will result in the caller having to deal with another checked exception.
>>> 
>>> 
>>> Thanks for any help
>>> Steve
>>> 
>>> 
>>> On 05/10/2012 05:06 PM, Craig Artley wrote:
>>> 
>>> 
>>> Hello, I want to take exceptions on the server and return them back to the client. For example, say the client's request leads to a run time exception like IllegalArgumentException. I think that TApplicationException with INTERNAL_ERROR is the way to do this, but I couldn't get it to work and I can't find any examples.
>>> 
>>> In my service handler, I check the args. If they are invalid, I threw a TApplicationException like this
>>> throw new TApplicationException(TApplicationException.INTERNAL_ERROR,"Illegal argument blah blah");
>>> 
>>> It still showed up in my client as a TTransportException:
>>> org.apache.thrift.transport.TTransportException
>>> at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132)
>>> 
>>> I'm sure I am just misunderstanding something. What am I missing? Can anyone provide an example of robust exception handling in the server to the client?
>>> 
>>> I read about it in THRIFT-378
>>> https://issues.apache.org/jira/browse/THRIFT-378
>>> 
>>> Regards,
>>> -craig
>> 
>> You can define your own exception types. Here's a real world example:
>> 
>> -----------------------------------------------------
>> File OurThriftException.thrift:
>> struct ExceptionInfoAll
>> {
>> 1: string name, /** The class name of the exception */
>> 2: string message, /** If not a OurCustomException, this is the result of what().
>> If OurCustomException, this is the result of ex.toString(). */
>> }
>> 
>> struct ExceptionInfoOurCustomException
>> {
>> 1: string errorCodeName, /** The name of the error, such as DeviceNotFound
>> This is specific to the exception class */
>> 2: i32 errorCodeValue, /** The numeric value of the error code */
>> 3: string description, /** The description string defined in the exception's EXCEPTION_TABLE */
>> 4: string debugMsg, /** The debug message attached to the exception at the throw point */
>> 5: string location, /** The location information that may have been attached at the throw point. */
>> }
>> 
>> struct ExceptionInfo
>> {
>> 1: ExceptionInfoAll defaultInfo, /** Available for any exception */
>> 2: optional ExceptionInfoOurCustomException ourInfo, /** Available only for OurCustomException */
>> }
>> 
>> exception OurThriftExceptionWire
>> {
>> 1: ExceptionInfo excInfo, /** The information extracted from the exception that was caught by the server. */
>> }
>> -----------------------------------------------------
>> 
>> 
>> Once you do this, you can define a service like this:
>> 
>> service MyService
>> {
>> returnType myCall ( args here) throws (1: OurThriftException. OurThriftExceptionWire ex),
>> }
>> 
>> On your server side, you do this (I have neglected to set the __isset values to make the code clearer.):
>> 
>> returnType myCall_handler (args)
>> {
>> 
>> try
>> {
>> do something
>> }
>> catch (OurCustomException &ex)
>> {
>> OurThriftExceptionWire wireEx;
>> 
>> wireEx.excInfo.defaultInfo = "OurCustomException";
>> wireEx.excInfo.defaultInfo.message = ex.what();
>> 
>> // Extract info from OurCustomException here and pack into wireEx.excInfo.ourInfo
>> 
>> throw wireEx;
>> }
>> catch (std::exception &ex)
>> {
>> OurThriftExceptionWire wireEx;
>> 
>> wireEx.excInfo.defaultInfo = "OurCustomException";
>> wireEx.excInfo.defaultInfo.message = ex.what();
>> 
>> throw wireEx;
>> 
>> }
>> }
>> 
>> And on your client side you do this:
>> 
>> try
>> {
>> myCall (args)
>> }
>> catch (OurThriftExceptionWire &ex)
>> {
>> // Now you have exception details from the server side. We would throw an exception type
>> // specific to the library where this code is, but it would contain all the info from
>> // ex.excInfo.
>> }
>> 
>> I hope that helps.
>> 
>> Best regards,
>> Rush
> 		 	   		  


RE: Using TApplicationException - need example

Posted by Craig Artley <ca...@hotmail.com>.
Rush, thanks for the reply and the example code. I got that working with Java server and clients without too much drama.

Still, when I read the THRIFT-378 (https://issues.apache.org/jira/browse/THRIFT-378) I get the feeling that it should not be this tedious. Quoting from the original description:

---
One workaround might be to add an InternalError exception and declare
 every method to throw that, but this would require wrapping each method
 implementation on the server with a try/catch/throw block, which is 
ugly and repetitive (especially if there are other try/catch blocks 
nested) – exactly the sort of code that Thrift is good at automating 
away.


I think the right fix would be for the server to catch runtime 
exceptions in the generated process methods and send back a 
TApplicationException.  This is what some other servers (e.g., Erlang) 
already do.---

So what we have done is essentially implement the "workaround": boilerplate code in every method to explicitly catch internal problems and throw a custom exception.

The original reporter really nailed in the last sentence - server should automatically catch run time exceptions and throw TApplicationExceptions to the client. The bug is marked as resolved for nearly 3 years, so I must be completely misunderstanding the intent.  Isn't it supposed to automatically toss back to the client a TApplicationException of type INTERNAL_ERROR? Do I really have to do that by hand in every single method? Do people have to do that with C++ servers too, or is this only a problem with Java servers?

It was supposedly fixed, but maybe I just don't understand the goal. When my sever hits a run time exception, the client just gets a cryptic TTransportException with no clue of what went wrong.

Regards,
  -craig

----------------------------------------
> Subject: Re: Using TApplicationException - need example
> From: rush@manbert.com
> Date: Thu, 17 May 2012 09:44:30 -0700
> To: user@thrift.apache.org
>
>
> On May 16, 2012, at 10:07 PM, Steve Angelovich wrote:
>
> > What is TApplicationException intended to be used for?
> >
> > Is there a mechanism in thrift to propagate a runtime exception from the server back to the client?
> >
> > How do others deal with a case where the caller has made an RPC call with an invalid argument. In Java I'd normally throw a IllegalArgumentException, is something like this possible in thrift or do I have to add another user defined exception type which will result in the caller having to deal with another checked exception.
> >
> >
> > Thanks for any help
> > Steve
> >
> >
> > On 05/10/2012 05:06 PM, Craig Artley wrote:
> >
> >
> > Hello, I want to take exceptions on the server and return them back to the client. For example, say the client's request leads to a run time exception like IllegalArgumentException. I think that TApplicationException with INTERNAL_ERROR is the way to do this, but I couldn't get it to work and I can't find any examples.
> >
> > In my service handler, I check the args. If they are invalid, I threw a TApplicationException like this
> > throw new TApplicationException(TApplicationException.INTERNAL_ERROR,"Illegal argument blah blah");
> >
> > It still showed up in my client as a TTransportException:
> > org.apache.thrift.transport.TTransportException
> > at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132)
> >
> > I'm sure I am just misunderstanding something. What am I missing? Can anyone provide an example of robust exception handling in the server to the client?
> >
> > I read about it in THRIFT-378
> > https://issues.apache.org/jira/browse/THRIFT-378
> >
> > Regards,
> > -craig
>
> You can define your own exception types. Here's a real world example:
>
> -----------------------------------------------------
> File OurThriftException.thrift:
> struct ExceptionInfoAll
> {
> 1: string name, /** The class name of the exception */
> 2: string message, /** If not a OurCustomException, this is the result of what().
> If OurCustomException, this is the result of ex.toString(). */
> }
>
> struct ExceptionInfoOurCustomException
> {
> 1: string errorCodeName, /** The name of the error, such as DeviceNotFound
> This is specific to the exception class */
> 2: i32 errorCodeValue, /** The numeric value of the error code */
> 3: string description, /** The description string defined in the exception's EXCEPTION_TABLE */
> 4: string debugMsg, /** The debug message attached to the exception at the throw point */
> 5: string location, /** The location information that may have been attached at the throw point. */
> }
>
> struct ExceptionInfo
> {
> 1: ExceptionInfoAll defaultInfo, /** Available for any exception */
> 2: optional ExceptionInfoOurCustomException ourInfo, /** Available only for OurCustomException */
> }
>
> exception OurThriftExceptionWire
> {
> 1: ExceptionInfo excInfo, /** The information extracted from the exception that was caught by the server. */
> }
> -----------------------------------------------------
>
>
> Once you do this, you can define a service like this:
>
> service MyService
> {
> returnType myCall ( args here) throws (1: OurThriftException. OurThriftExceptionWire ex),
> }
>
> On your server side, you do this (I have neglected to set the __isset values to make the code clearer.):
>
> returnType myCall_handler (args)
> {
>
> try
> {
> do something
> }
> catch (OurCustomException &ex)
> {
> OurThriftExceptionWire wireEx;
>
> wireEx.excInfo.defaultInfo = "OurCustomException";
> wireEx.excInfo.defaultInfo.message = ex.what();
>
> // Extract info from OurCustomException here and pack into wireEx.excInfo.ourInfo
>
> throw wireEx;
> }
> catch (std::exception &ex)
> {
> OurThriftExceptionWire wireEx;
>
> wireEx.excInfo.defaultInfo = "OurCustomException";
> wireEx.excInfo.defaultInfo.message = ex.what();
>
> throw wireEx;
>
> }
> }
>
> And on your client side you do this:
>
> try
> {
> myCall (args)
> }
> catch (OurThriftExceptionWire &ex)
> {
> // Now you have exception details from the server side. We would throw an exception type
> // specific to the library where this code is, but it would contain all the info from
> // ex.excInfo.
> }
>
> I hope that helps.
>
> Best regards,
> Rush
 		 	   		  

Re: Using TApplicationException - need example

Posted by Rush Manbert <ru...@manbert.com>.
On May 16, 2012, at 10:07 PM, Steve Angelovich wrote:

> What is TApplicationException intended to be used for?
> 
> Is there a mechanism in thrift to propagate a runtime exception from the server back to the client?
> 
> How do others deal with a case where the caller has made an RPC call with an invalid argument.  In Java I'd normally throw a IllegalArgumentException, is something like this possible in thrift or do I have to add another user defined exception type which will result in the caller having to deal with another checked exception.
> 
> 
> Thanks for any help
> Steve
> 
> 
> On 05/10/2012 05:06 PM, Craig Artley wrote:
> 
> 
> Hello, I want to take exceptions on the server and return them back to the client. For example, say the client's request leads to a run time exception like IllegalArgumentException. I think that TApplicationException with INTERNAL_ERROR is the way to do this, but I couldn't get it to work and I can't find any examples.
> 
> In my service handler, I check the args.  If they are invalid, I threw a TApplicationException like this
>  throw new TApplicationException(TApplicationException.INTERNAL_ERROR,"Illegal argument blah blah");
> 
> It still showed up in my client as a TTransportException:
> org.apache.thrift.transport.TTransportException
>    at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132)
> 
> I'm sure I am just misunderstanding something.  What am I missing? Can anyone provide an example of robust exception handling in the server to the client?
> 
> I read about it in THRIFT-378
> https://issues.apache.org/jira/browse/THRIFT-378
> 
> Regards,
>  -craig

You can define your own exception types. Here's a real world example:

-----------------------------------------------------
File OurThriftException.thrift:
struct ExceptionInfoAll
{
	1: string 	name,		/** The class name of the exception */
	2: string 	message,	/** If not a OurCustomException, this is the result of what().
					    If OurCustomException, this is the result of ex.toString(). */
}

struct ExceptionInfoOurCustomException
{
	1: string 	errorCodeName,	/** The name of the error, such as DeviceNotFound
								    This is specific to the exception class */
	2: i32		errorCodeValue,	/** The numeric value of the error code */
	3: string	description,	/** The description string defined in the exception's EXCEPTION_TABLE */
	4: string	debugMsg,	/** The debug message attached to the exception at the throw point */
	5: string	location,	/** The location information that may have been attached at the throw point. */
}

struct ExceptionInfo
{
	1: ExceptionInfoAll 				defaultInfo,		/** Available for any exception */
	2: optional ExceptionInfoOurCustomException	ourInfo,		/** Available only for OurCustomException */
}

exception OurThriftExceptionWire
{
	1: ExceptionInfo 			excInfo,	/** The information extracted from the exception that was caught by the server. */
}
-----------------------------------------------------


Once you do this, you can define a service like this:

service MyService
{
	returnType myCall ( args here)  throws (1: OurThriftException. OurThriftExceptionWire ex),
}

On your server side, you do this (I have neglected to set the __isset values to make the code clearer.):

returnType myCall_handler (args)
{

	try
	{
		do something
	}
	catch (OurCustomException &ex)
	{
		OurThriftExceptionWire wireEx;

		wireEx.excInfo.defaultInfo = "OurCustomException";
		wireEx.excInfo.defaultInfo.message = ex.what();

		// Extract info from OurCustomException here and pack into wireEx.excInfo.ourInfo

		throw wireEx;
	}
	catch (std::exception &ex)
	{
		OurThriftExceptionWire wireEx;

		wireEx.excInfo.defaultInfo = "OurCustomException";
		wireEx.excInfo.defaultInfo.message = ex.what();

		throw wireEx;

	}
}

And on your client side you do this:

try
{
	myCall (args)
}
catch (OurThriftExceptionWire &ex)
{
	// Now you have exception details from the server side. We would throw an exception type
	// specific to the library where this code is, but it would contain all the info from
	// ex.excInfo.
}

I hope that helps.

Best regards,
Rush

Re: Using TApplicationException - need example

Posted by Steve Angelovich <SA...@lgc.com>.
What is TApplicationException intended to be used for?

Is there a mechanism in thrift to propagate a runtime exception from the server back to the client?

How do others deal with a case where the caller has made an RPC call with an invalid argument.  In Java I'd normally throw a IllegalArgumentException, is something like this possible in thrift or do I have to add another user defined exception type which will result in the caller having to deal with another checked exception.


Thanks for any help
Steve


On 05/10/2012 05:06 PM, Craig Artley wrote:


Hello, I want to take exceptions on the server and return them back to the client. For example, say the client's request leads to a run time exception like IllegalArgumentException. I think that TApplicationException with INTERNAL_ERROR is the way to do this, but I couldn't get it to work and I can't find any examples.

In my service handler, I check the args.  If they are invalid, I threw a TApplicationException like this
  throw new TApplicationException(TApplicationException.INTERNAL_ERROR,"Illegal argument blah blah");

It still showed up in my client as a TTransportException:
org.apache.thrift.transport.TTransportException
    at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132)

I'm sure I am just misunderstanding something.  What am I missing? Can anyone provide an example of robust exception handling in the server to the client?

I read about it in THRIFT-378
https://issues.apache.org/jira/browse/THRIFT-378

Regards,
  -craig

----------------------------------------------------------------------
This e-mail, including any attached files, may contain confidential and privileged information for the sole use of the intended recipient.  Any review, use, distribution, or disclosure by others is strictly prohibited.  If you are not the intended recipient (or authorized to receive information for the intended recipient), please contact the sender by reply e-mail and delete all copies of this message.