Appending traceback from exception in child thread

E

Edd

Hi folks,

I have a some threadpool code that works like this :

tp = ThreadPool(number_of_threads)
futures = [tp.future(t) for t in tasks] # each task is callable
for f in futures:
print f.value() # <-- may propagate an exception

The idea being that a Future object represents a value that may or may
not have been computed yet and the .value() method will block until
that value is ready.

As the comment on the last line indicates, looking at the .value() of
a Future may give the return value of the associated task, or it may
also propagate an exception that was raised in a child thread.

Inside the implementation I store caught exceptions with code that
looks something like:

try:
self.return_value = self.task()
except:
self.exception = sys.exc_info()[1]

The problem I have is that when an exception is propagated in to the
parent thread by re-raising it, the part of the traceback from the
child thread is lost. So if the program dies due to such an exception,
I can't see what caused it by examining the printed traceback.

To solve this problem, I could of course grab the traceback in the
child thread and create some kind of custom exception that stashes the
trace inside. This could then be caught on the fringes of my code in
order to combine the tracebacks of parent and child together before
printing it. But I was wondering if there might be a nicer way that
keeps the original exception object. Perhaps something akin to gluing
the tracebacks together at the point where the exception is re-raised?

Kind regards,

Edd
 
C

Chris Mellon

Hi folks,

I have a some threadpool code that works like this :

   tp = ThreadPool(number_of_threads)
   futures = [tp.future(t) for t in tasks] # each task is callable
   for f in futures:
       print f.value() # <-- may propagate an exception

The idea being that a Future object represents a value that may or may
not have been computed yet and the .value() method will block until
that value is ready.

As the comment on the last line indicates, looking at the .value() of
a Future may give the return value of the associated task, or it may
also propagate an exception that was raised in a child thread.

Inside the implementation I store caught exceptions with code that
looks something like:

   try:
       self.return_value = self.task()
   except:
       self.exception = sys.exc_info()[1]

The problem I have is that when an exception is propagated in to the
parent thread by re-raising it, the part of the traceback from the
child thread is lost. So if the program dies due to such an exception,
I can't see what caused it by examining the printed traceback.

To solve this problem, I could of course grab the traceback in the
child thread and create some kind of custom exception that stashes the
trace inside. This could then be caught on the fringes of my code in
order to combine the tracebacks of parent and child together before
printing it. But I was wondering if there might be a nicer way that
keeps the original exception object. Perhaps something akin to gluing
the tracebacks together at the point where the exception is re-raised?

Kind regards,

Edd


Take a look at the Deferred and Failure objects from Twisted. Deferred
is a deferred result with callback (basically a Future without the
blocking interface), and Failure is an asynchronous exception object.
 
G

Gabriel Genellina

As the comment on the last line indicates, looking at the .value() of
a Future may give the return value of the associated task, or it may
also propagate an exception that was raised in a child thread.

Inside the implementation I store caught exceptions with code that
looks something like:

try:
self.return_value = self.task()
except:
self.exception = sys.exc_info()[1]

The problem I have is that when an exception is propagated in to the
parent thread by re-raising it, the part of the traceback from the
child thread is lost. So if the program dies due to such an exception,
I can't see what caused it by examining the printed traceback.

To solve this problem, I could of course grab the traceback in the
child thread and create some kind of custom exception that stashes the
trace inside. This could then be caught on the fringes of my code in
order to combine the tracebacks of parent and child together before
printing it. But I was wondering if there might be a nicer way that
keeps the original exception object. Perhaps something akin to gluing
the tracebacks together at the point where the exception is re-raised?

You could use the 3-argument form of the raise statement:
http://docs.python.org/reference/simple_stmts.html#the-raise-statement

There is a problem: remember that the traceback object keeps a reference
to all previous frames -- that means, all local variables along the whole
stack of called functions are kept alive until you delete the traceback
object. And depending on your application, that might involve thousand of
objects "artificially" alive for an undeterminate period of time...

It it's just for logging/debugging and you don't require access to the
"live" objects, using a custom attribute in the exception object to store
a list of strings (like the one traceback.extract_tb builds) may be a
better idea.
 
D

Diez B. Roggisch

Edd said:
Hi folks,

I have a some threadpool code that works like this :

tp = ThreadPool(number_of_threads)
futures = [tp.future(t) for t in tasks] # each task is callable
for f in futures:
print f.value() # <-- may propagate an exception

The idea being that a Future object represents a value that may or may
not have been computed yet and the .value() method will block until
that value is ready.

As the comment on the last line indicates, looking at the .value() of
a Future may give the return value of the associated task, or it may
also propagate an exception that was raised in a child thread.

Inside the implementation I store caught exceptions with code that
looks something like:

try:
self.return_value = self.task()
except:
self.exception = sys.exc_info()[1]

The problem I have is that when an exception is propagated in to the
parent thread by re-raising it, the part of the traceback from the
child thread is lost. So if the program dies due to such an exception,
I can't see what caused it by examining the printed traceback.

To solve this problem, I could of course grab the traceback in the
child thread and create some kind of custom exception that stashes the
trace inside. This could then be caught on the fringes of my code in
order to combine the tracebacks of parent and child together before
printing it. But I was wondering if there might be a nicer way that
keeps the original exception object. Perhaps something akin to gluing
the tracebacks together at the point where the exception is re-raised?

If you are only interested in the original traceback, you can get that
with the traceback.format function.

Then you don't need to re-raise it in the main-thread, or if so, use the
formatted stacktrace as payload to an exception.

Diez
 
E

Edd

You could use the 3-argument form of the raise statement:http://docs.python.org/reference/simple_stmts.html#the-raise-statement

Ah! When did that get there? :)
There is a problem: remember that the traceback object keeps a reference  
to all previous frames -- that means, all local variables along the whole  
stack of called functions are kept alive until you delete the traceback  
object. And depending on your application, that might involve thousand of  
objects "artificially" alive for an undeterminate period of time...

Yes, that may be problematic, I'll have to experiment.

Thanks to everyone's help here, I have plenty of alternatives if it
turns out to be problematic. Your comments are all greatly appreciated
-- thanks!

Kind regards,

Edd
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top