Search code examples
pythonpython-multiprocessing

How to pass exception from one process to another?


I want to raise an exception in the upload function if the running status in stop function is 'stopped'. This doesn't seem to work. I am using Pipe to pass the exception. What is wrong?

def upload(instances, u1):
    for instance in instance:
        try:
            u1.recv()
            #do_something
        except:
            #do_something_else
            continue         

def stop(instances, s1):
    for instance in instances:
        RunningStatus = instance[4]
        if RunningStatus.lower() == 'stopped'.lower():
            s1.send(Exception) # I want to raise exception in upload function 
                               # from here

if __name__ == '__main__':
    s1, u1 = multiprocessing.Pipe()
    s = multiprocessing.Process(target = stop, args = (instances, s1,))
    u = multiprocessing.Process(target = upload, args = (instances, u1))
    s.start()
    u.start()
    u.join()

Solution

  • Here's an example of how you could send Exception objects from one process to another. I also tried sending complete exception information (as returned by sys.exc_info), but, reasonably enough, this fails. One could always format the traceback info to a string and send that instead (see the traceback module).

    Tested on Ubuntu 14.04 Python 2.7, 3.4 (Ubuntu-provided), and 3.5 (Continuum).

    from __future__ import print_function
    
    import sys
    import multiprocessing
    import time
    
    def upload(u1):
        i=0
        try:
            while True:
                print('>upload>',i)
                i+=1
                if u1.poll():
                    # tvt = u1.recv()
                    # raise tvt[0], tvt[1], tvt[2] # Python 2.7
                    e = u1.recv()
                    raise e
                time.sleep(0.1)
        except Exception as e:
            print('Exception caught:',e)
            print('exiting')
    
    def stop(s1):
        try:
            while True:
                for j in range(100,110):
                    time.sleep(0.1)
                    if 105==j:
                        raise RuntimeError("oh dear at j={}".format(j))
        except Exception as e:
            # tvt = sys.exc_info()
            # s1.send(tvt) # doesn't work; tracebacks are not pickle'able
            s1.send(e)
    
    if __name__ == '__main__':
        s1, u1 = multiprocessing.Pipe()
        s = multiprocessing.Process(target = stop, args = (s1,))
        u = multiprocessing.Process(target = upload, args = (u1,))
        s.start()
        u.start()
        u.join()
    

    Output:

    >upload> 0
    >upload> 1
    >upload> 2
    >upload> 3
    >upload> 4
    >upload> 5
    >upload> 6
    Exception caught: oh dear at j=105
    exiting