Beispiel #1
0
async def brain(thread_executor, id_repo, tarea_repo, comando_repo, humor_repo,
                accion_repo, evento_repo):
    logger = LoggerRepository('brain')
    try:

        loop = asyncio.get_event_loop()
        blocking_tasks = [
            loop.run_in_executor(thread_executor,
                                 Sensor(humor_repo).listen_to_task_result,
                                 evento_repo),
            loop.run_in_executor(thread_executor,
                                 Ejecutor().listen_for_next_tarea, id_repo,
                                 tarea_repo, evento_repo, accion_repo),
            loop.run_in_executor(thread_executor,
                                 Comander().listen_to_command, comando_repo,
                                 tarea_repo, accion_repo, evento_repo)
        ]

        logger.debug("Preparados los threads")
        return blocking_tasks
    except asyncio.CancelledError:
        pass

    except Exception as mgr_ex:
        logger.error(f"Excecion en brain: {mgr_ex}")
Beispiel #2
0
class Comander(ComanderInterface):
    def __init__(self):
        self.logger = LoggerRepository('comander')

    def enqueue_task(self, tarea: Tarea, tarea_repo: TareaRepositoryInterface):
        self.logger.debug(f"Encolando tarea {tarea}")
        tarea_repo.append(tarea)

    def listen_to_command(self, repo_command: ComandoRepositoryInterface,
                          tarea_repo: TareaRepositoryInterface,
                          accion_repo: AccionRepositoryInterface,
                          evento_repo: EventRepositoryInterface):
        self.logger.debug("Escuchando por nuevo comando")
        #while True:
        for cmd in repo_command.next_comando():
            try:
                #cmd = repo_command.next_comando()
                if isinstance(cmd, ComandoNuevaTarea):
                    self.logger.debug(
                        "Recibido comando de tipo ComandoNuevaTarea")
                    self.enqueue_task(cmd.tarea, tarea_repo)
                    self.logger.debug("Escuchando por nuevo comando")
                    continue
                if isinstance(cmd, ComandoNuevaAccion):
                    self.logger.debug(
                        "Recibido comando de tipo ComandoNuevaAccion")
                    accion_repo.append_accion(accion=cmd.accion,
                                              evento_repo=evento_repo)
                    self.logger.debug("Escuchando por nuevo comando")
                    continue
                raise CommandNotImplemented(cmd)

            except Exception as ex:
                self.logger.error(ex)
                traceback.print_exc()
class EventoRepository(EventRepositoryInterface):
    def __init__(self):
        self.logger = LoggerRepository('comando_repo')

    def pub_event(self, evento):
        try:
            eventos.put(evento)
            return True
        except Exception:
            return False

    def subscribe_event(self):
        while True:
            try:
                yield eventos.get(block=True, timeout=QUEUE_TIMEOUT)
            except Exception as ex:
                self.logger.error(ex)
                continue
Beispiel #4
0
class Sensor(SensorInterface):
    def __init__(self, humor_repo: EstadoHumorRepositoryInterface):
        self.logger = LoggerRepository('sensor')
        self.humor_repo = humor_repo

    def listen_to_task_result(self, evento_repo: EventRepositoryInterface):
        try:
            self.logger.debug("Escuchando a resultado de tarea")
            for evento in evento_repo.subscribe_event():
                if isinstance(evento, AccionTerminada):
                    self.logger.debug(
                        f"Se ha terminado la tarea: {evento.tarea_idd}, resultado: {evento.resultado}"
                    )
                    self.update_humor_from_task_result(evento.resultado,
                                                       self.humor_repo,
                                                       evento_repo)
                self.logger.debug("Escuchando por un resultado de tarea")
        except Exception as ex:
            self.logger.error(ex)
            traceback.print_exc()

    def update_humor_from_task_result(
            self, resultado: ResultadoAccion,
            humor_repo: EstadoHumorRepositoryInterface,
            evento_repo: EventRepositoryInterface):
        try:
            print(resultado)
            humor_repo.mejora() if resultado.is_good() else humor_repo.empeora(
            )
            self.logger.debug("El humor ha cambiado a : {}".format(
                humor_repo.como_estas()))
            evento_repo.pub_event(
                EstadoHumorCambiado(
                    idd=Idd(Idefier()),
                    nuevo_estado_humor=humor_repo.como_estas()))
        except Exception as ex:
            self.logger.error(ex)
            traceback.print_exc()
Beispiel #5
0
class Comander(ComanderInterface):
    def __init__(self):
        self.logger = LoggerRepository('comander')

    def enqueue_task(self, tarea: Tarea, tarea_repo: TareaRepositoryInterface):
        self.logger.debug(f"Encolando tarea {tarea}")
        tarea_repo.append(tarea)

    def listen_to_command(self, repo_command: ComandoRepositoryInterface,
                          tarea_repo: TareaRepositoryInterface,
                          accion_repo: AccionRepositoryInterface,
                          evento_repo: EventRepositoryInterface):
        self.logger.debug("Escuchando por nuevo comando")
        #while True:
        for cmd in repo_command.next_comando():
            try:
                #cmd = repo_command.next_comando()
                if isinstance(cmd, ComandoNuevaTarea):
                    self.logger.debug(
                        "Recibido comando de tipo ComandoNuevaTarea")
                    self.enqueue_task(cmd.tarea, tarea_repo)
                    self.logger.debug("Escuchando por nuevo comando")
                    continue
                if isinstance(cmd, ComandoNuevaAccion):
                    #TODO la persistencia de la Acción debe ser llevada a cabo por el Aggregate Accion, que se ejecuta en el
                    # service Ejecutor. En el modo monoproceso no es tan importante, en el modo multiproceso (para garantizar
                    # la separación de bases de datos entre microservicios) si es relevante cambiar la responsabilidad
                    self.logger.debug(
                        "Recibido comando de tipo ComandoNuevaAccion")
                    accion_repo.append_accion(accion=cmd.accion,
                                              evento_repo=evento_repo)
                    self.logger.debug("Escuchando por nuevo comando")
                    continue
                raise CommandNotImplemented(cmd)

            except Exception as ex:
                self.logger.error(ex)
                traceback.print_exc()
class AccionRepository(AccionRepositoryInterface):
    def __init__(self):
        self.logger = LoggerRepository('accion_repo')
        self.acciones = list()

    def get_actiones_by_type(self, tipo: TipoAccion):
        for accion in self.acciones:
            if accion.tipo == tipo:
                yield accion

    def get_all(self):
        return tuple(a for a in self.acciones)


    def get_accion_by_id(self, idd: Idd):
        self.logger.debug(f"Buscamos accion con la idd: {idd}")
        for accion in self.acciones:
            self.logger.debug(f"Miramos si esta accion {accion} corresponde con id: {idd}")
            if accion.idd == idd:
                return accion
        raise AccionNotFoundError(f"idd={idd}")

    def get_acciones_buen_humor(self):
        return (a for a in self.get_acciones_by_type(TipoAccion(TipoAccion.BUEN_HUMOR)))
    
    def get_acciones_mal_humor(self):
        return (a for a in self.get_acciones_by_type(TipoAccion(TipoAccion.MAL_HUMOR)))

    def del_accion(self, accion: Accion):
        self.acciones.remove(accion)
            
    def rollback_append_accion(self, accion: Accion):
        self.logger.debug("Rolling back append accion")
        self.del_accion(accion)

    def append_accion(self, accion: Accion, evento_repo: EventRepositoryInterface):
        try:
            self.logger.debug("Apending nueva accion")
            self.acciones.append(accion)
            emitido = evento_repo.pub_event(accion)
            if not emitido:
                self.rollback_append_accion(accion=accion)
        except Exception as ex:
            self.logger.error(ex)
            self.rollback_append_accion(accion=accion)

    def to_json(self, accion: Accion):
        return json.dumps({
            "idd": f"{accion.idd}",
            "nombre": accion.nombre,
            "script_url": accion.script_url,
            "tipo": f"{accion.tipo}"
        })

    def from_json(self, json_str_accion: str):
        json_accion = json.loads(json_str_accion)
        return Accion(
            idd=Idd(idefier=Idefier(), idd_str=json_accion['idd']),
            nombre=json_accion['nombre'],
            script_url=json_accion['script_url'],
            tipo=json_accion['tipo']
        )

    def get_all_json(self):
        return tuple(json.loads(self.to_json(accion)) for accion in self.get_all())
class ComandoRepository(ComandoRepositoryInterface):
    def __init__(self):
        self.logger = LoggerRepository('comando_repo')
        self.comandos = get_queue(COMANDOS_QUEUE_NAME)

    @staticmethod
    def serialize(comando: Comando) -> str:
        if isinstance(comando, ComandoNuevaTarea):
            return json.dumps({
                "clase": "ComandoNuevaTarea",
                "idd": str(comando.idd),
                "tarea": TareaRepository.to_json(comando.tarea)
            })
        if isinstance(comando, ComandoNuevaAccion):
            return json.dumps({
                "clase":
                "ComandoNuevaAccion",
                "idd":
                str(comando.idd),
                "accion":
                AccionRepository.to_json(accion=comando.accion)
            })

    @staticmethod
    def deserialize_comando_nueva_tarea(comando: dict) -> ComandoNuevaTarea:
        return ComandoNuevaTarea(idd=Idd(Idefier(), idd_str=comando['idd']),
                                 tarea=TareaRepository.deserialize(
                                     comando['tarea']))

    @staticmethod
    def deserialize_comando_nueva_accion(comando: dict) -> ComandoNuevaAccion:
        return ComandoNuevaAccion(idd=Idd(Idefier(), idd_str=comando['idd']),
                                  accion=AccionRepository.deserialize(
                                      comando['accion']))

    def next_comando(self):
        while True:
            self.logger.debug("Esperamos por nuevo comando")
            cmd = self.comandos.receive_messages(
                MaxNumberOfMessages=MAX_NUMBER_OF_MESSAGES,
                WaitTimeSeconds=POLL_TIME,
                AttributeNames=['MessageDeduplicationId', 'MessageGroupId'])

            for cc in cmd:
                c = json.loads(cc.body)
                cc.delete()
                if c['clase'] == "ComandoNuevaTarea":
                    yield ComandoRepository.deserialize_comando_nueva_tarea(c)
                if c['clase'] == "ComandoNuevaAccion":
                    yield ComandoRepository.deserialize_comando_nueva_accion(c)

    def send_comando(self, comando):
        try:
            self.logger.debug(f"Intentamos enviar el comando::: {comando}")
            response = self.comandos.send_message(
                MessageBody=ComandoRepository.serialize(comando),
                MessageGroupId=MESSAGE_GROUP_ID,
                MessageDeduplicationId=str(comando.idd))

            self.logger.debug(
                f"Comando enviado: [{comando}], messageid: [{response['MessageId']}]"
            )
        except Exception as ex:
            self.logger.error(f"Error intentando enviar un comando: {ex}")
Beispiel #8
0
class Ejecutor(EjecutorInterface):
    def __init__(self):
        self.logger = LoggerRepository('ejecutor')

    def listen_for_next_tarea(self, id_repo: IdefierInterface,
                              tarea_repo: TareaRepositoryInterface,
                              evento_repo: EventRepositoryInterface,
                              accion_repo: AccionRepositoryInterface):
        try:
            self.logger.debug("Escuchando por nueva tarea")
            for tarea in tarea_repo.next_tarea():

                self.ejecuta_tarea(tarea=tarea,
                                   id_repo=id_repo,
                                   evento_repo=evento_repo,
                                   accion_repo=accion_repo)
                self.logger.debug("Escuchando por nueva tarea")
        except Exception as ex:
            self.logger.error(ex)
            traceback.print_exc()

    def ejecuta_tarea(self, tarea: Tarea, id_repo: IdefierInterface,
                      evento_repo: EventRepositoryInterface,
                      accion_repo: AccionRepositoryInterface):

        evento = None
        resultado = None
        try:
            accionid = tarea.accionid
            print(f"ha llegado el accion id: {accionid}")
            idd = Idd(idefier=id_repo, idd_str=accionid)
            self.logger.debug(
                f"Intentamos ejecutar ---- accionid: {idd}, repo: {accion_repo}"
            )
            accion = accion_repo.get_accion_by_id(idd)
            self.logger.debug(f"Ejecutamos: {accion} (dormimos 10s)")

            #TODO implementar realmente la ejecucion, ahora solo hay un ejemplo
            time.sleep(10)
            self.logger.debug("despertamos, tarea ejecutada")

            if int(tarea.nombre) > 0:
                resultado = ResultadoAccion(codigo=CodigoResultado(
                    codigo=CodigoResultado.BUEN_RESULTADO),
                                            msg="la tarea ha ido bien")
            else:
                resultado = ResultadoAccion(codigo=CodigoResultado(
                    codigo=CodigoResultado.MAL_RESULTADO),
                                            msg="la tarea ha ido mal")
            evento = AccionTerminada(idd=Idd(idefier=Idefier()),
                                     tarea_idd=tarea.idd,
                                     resultado=resultado)
            evento_repo.pub_event(evento=evento)

        except AccionNotFoundError as exx:
            self.logger.error(f"No se ha encontrado la Accion {exx}")
            resultado = ResultadoAccion(
                codigo=CodigoResultado(codigo=CodigoResultado.MAL_RESULTADO),
                msg=f"No existe la tarea {exx}")
            evento = AccionTerminada(idd=Idd(idefier=Idefier()),
                                     tarea_idd=tarea.idd,
                                     resultado=resultado)
            evento_repo.pub_event(evento=evento)
        except Exception as ekk:
            self.logger.error(f"Error no identificado: {ekk}")
class EventoRepository(EventRepositoryInterface):
    def __init__(self):
        self.logger = LoggerRepository('evento_repo')
        self.eventos = get_queue(EVENTOS_QUEUE_NAME)

    @staticmethod
    def to_json(evento: Evento):
        if isinstance(evento, AccionTerminada):
            return {
                "clase": "AccionTerminada",
                "idd": str(evento.idd),
                "tarea_idd": str(evento.tarea_idd),
                "resultado": {
                    "codigo": str(evento.resultado.codigo),
                    "msg": evento.resultado.msg
                }
            }
        if isinstance(evento, NuevaAccionCreada):
            return {
                "clase": "NuevaAccionCreada",
                "idd": str(evento.idd),
                "accion_idd": str(evento.accion_idd),
                "accion_nombre": str(evento.accion_nombre)
            }
        if isinstance(evento, EstadoHumorCambiado):
            return {
                "clase": "EstadoHumorCambiado",
                "idd": str(evento.idd),
                "nuevo_estado_humor": evento.nuevo_estado_humor
            }
        raise EventoNotImplemented(evento)

    @staticmethod
    def from_json(evento: dict):
        if evento['clase'] == 'AccionTerminada':
            evento.pop('clase')
            return AccionTerminada(**evento)

        if evento['clase'] == 'EstadoHumorCambiado':
            evento.pop('clase')
            return EstadoHumorCambiado(**evento)

        if evento['clase'] == 'NuevaAccionCreada':
            evento.pop('clase')
            return NuevaAccionCreada(**evento)

    @staticmethod
    def serialize(evento: dict):
        return json.dumps(EventoRepository.to_json(evento))

    @staticmethod
    def deserialize(evento: str):
        return EventoRepository.from_json(json.loads(evento))

    def pub_event(self, evento: Evento):
        try:
            evs = EventoRepository.serialize(evento)
            self.logger.debug(f"Intentado enviar el evento: {evs}")

            self.eventos.send_message(MessageBody=evs,
                                      MessageGroupId=MESSAGE_GROUP_ID,
                                      MessageDeduplicationId=str(evento.idd))
            self.logger.debug("Evento enviado")
            return True

        except EventoNotImplemented as exx:
            raise exx

        except Exception as ex:
            self.logger.error(f"Sending event: {ex}")
            return False

    def subscribe_event(self):
        while True:
            try:
                self.logger.debug("Esperando por eventos")
                msg = self.eventos.receive_messages(
                    MaxNumberOfMessages=MAX_NUMBER_OF_MESSAGES,
                    WaitTimeSeconds=POLL_TIME,
                    AttributeNames=[
                        'MessageDeduplicationId', 'MessageGroupId'
                    ])
                #self.logger.debug(f"Han llegado eventos: {msg}")
                for cc in msg:
                    if cc is None:
                        break
                    c = json.loads(cc.body)
                    cc.delete()
                    yield EventoRepository.from_json(c)

            except Exception as ex:
                self.logger.error(ex)
                continue
class AccionRepository(AccionRepositoryInterface):
    def __init__(self):
        self.logger = LoggerRepository('accion_repo')
        self.acciones = get_dynamodb_acciones_table()

    def purge_table(self):
        try:
            self.logger.debug(f"Eliminamos todos los elementos de la tabla")
            response = self.acciones.scan()
        except ClientError as ex:
            self.logger.error(f"Error in get_by_type: {ex}")
            return None
        else:
            for each in response['Items']:
                self.acciones.delete_item(Key={'idd': each['idd']})

    @staticmethod
    def to_json(accion: Accion) -> dict:
        print(accion)
        return {
            "idd": str(accion.idd),
            "nombre": accion.nombre,
            "script_url": accion.script_url,
            "tipo": str(accion.tipo)
        }

    @staticmethod
    def serialize(accion: Accion) -> str:
        return json.dumps(AccionRepository.to_json(accion))

    @staticmethod
    def deserialize(accion: dict) -> Accion:
        return Accion(**accion)

    def get_acciones_by_type(self, tipo: TipoAccion):
        try:
            self.logger.debug(f"Buscamos accion con el tipo: {tipo}")
            response = self.acciones.scan(
                FilterExpression=Key('tipo').eq(str(tipo)))
        except ClientError as ex:
            self.logger.error(f"Error in get_by_type: {ex}")
            return None
        else:
            for i in response['Items']:
                yield AccionRepository.deserialize(i)

    def get_all(self):
        return tuple(
            AccionRepository.deserialize(a)
            for a in self.acciones.scan()['Items'])

    def get_accion_by_id(self, idd: Idd):

        try:
            self.logger.debug(f"Buscamos accion con la idd: {idd}")
            response = self.acciones.get_item(Key={'idd': str(idd)})
        except ClientError as ex:
            self.logger.error(f"Error in get_by_id: {ex}")
            return None
        else:
            if not 'Item' in response:
                raise AccionNotFoundError(idd)

            return AccionRepository.deserialize(response['Item'])

    def get_acciones_buen_humor(self):
        return (a for a in self.get_acciones_by_type(
            TipoAccion(TipoAccion.BUEN_HUMOR)))

    def get_acciones_mal_humor(self):
        return (a for a in self.get_acciones_by_type(
            TipoAccion(TipoAccion.MAL_HUMOR)))

    def del_accion(self, accion: Accion):

        self.acciones.delete_item(Key={"idd": str(accion.idd)})

    def rollback_append_accion(self, accion: Accion):
        self.logger.debug("Rolling back append accion")

        self.del_accion(accion)

    def append_accion(self, accion: Accion,
                      evento_repo: EventRepositoryInterface):
        try:
            self.logger.debug(
                f"Apending nueva accion: tabla: {self.acciones} item: {AccionRepository.to_json(accion)}"
            )
            self.acciones.put_item(Item=AccionRepository.to_json(accion))
            emitido = evento_repo.pub_event(
                NuevaAccionCreada(idd=Idd(idefier=Idefier()),
                                  accion_idd=accion.idd,
                                  accion_nombre=accion.nombre))
            if not emitido:
                self.rollback_append_accion(accion=accion)
        except Exception as ex:
            self.logger.error(ex)
            self.rollback_append_accion(accion=accion)

    def get_all_json(self):
        return tuple(
            AccionRepository.to_json(accion) for accion in self.get_all())