miércoles, 28 de noviembre de 2012

Lanzar procesos en background

0 comentarios
 
Muchas veces nos resultará útil lanzar algún tipo de proceso en background con tal de no bloquear el navegador. Por ejemplo, procesos que impliquen actualización o creación de muchos objetos

Para ello, podemos utilizar los siguientes fragmentos de código para hacerlo

1-Por un lado, crearemos un adaptador o incluiremos este código para gestionar la llamada a procesos externos

class CommandLauncher(threading.Thread):
    def __init__(self, command,params=[]):
        threading.Thread.__init__(self)
        self.command = command
        self.result  = None
        if len(params):
            self.command = '%s %s'%(self.command,' '.join(params))       
       
    def run(self):       
        command_in, command_out = os.popen4(self.command, bufsize=0)       
        self.result = command_out.read()       
        command_in.close()       
        command_out.close()
       
    def abort(self):
        import os, sys
        if sys.platform == 'win32':
            os.abort()
        my_pid = str(os.getpid())
        command_in, command_out = os.popen4("/bin/ps -Af | /bin/grep %s | /bin/grep -v grep" % my_pid) 
        result = str(command_out.read())
        for line in result.split('\n'):
            while line.find('  ') > -1:
                line = line.replace('  ',' ')
            parts = line.split(' ')
            if len(parts)>1 and parts[2] == my_pid:
                # A child process to be killed
                os.kill(long(parts[1]), 9)
                os.waitpid(long(parts[1]), 0)
        command_in.close()
        command_out.close()


2- Dentro de nuestro código, haríamos una llamada de este tipo:

def miProcesoEnBatch(self,portal):
        try:                       
            command = '/usr/local/kmkey/zope/bin/zopectl run miscript.py'
            thread = CommandLauncher(command)
            thread.start()           
        except:  
             llamar a algun proceso que reporte el error(log propio o envío de mail)
             raise "Export error", thread.result
        return

Con esto , conseguimos hacer una llamada a un proceso externo desde nuestro navegador (en el proceso externo deberemos montar algún sistema para enviar aviso de que ha finalizado o ha dado error)

Un ejemplo de proceso externo sería este:


if __name__ == "__main__":   
    try:  
        import_products()
        #low priority   
        os.nice(5)   
       
        app = makerequest(app)
        site = app.unrestrictedTraverse('mi_sitio_kmkey')
        user = site.acl_users.getUser('manager').__of__(site.acl_users)
        newSecurityManager({}, user)
        app = makerequest(app)
        site = app.unrestrictedTraverse('mi_sitio_kmkey')              

        #todo mi proceso aquí#  (con commits parciales)
        get_transaction().commit()       
    except:  
        (exc, msg, tb) = sys.exc_info()
        out = StringIO()
        traceback.print_exception(exc,msg,tb,None,out)
        out.seek(0)
        body = str(out.read())
        #montar algún sistema para reportar errores, ya
        #sea con log propio, envió de mail o logger de zope
        escribelog(body)
        enviarMail(site,subject="Traceback Error a importació de matrícules",body=body)
        logger.error("Importar matricules Traceback:\n%s", body)



Leave a Reply