Пример #1
0
    def target(sequence, values_cache, errors_cache, q_in, q_out,
               timeout, start_hook):
        if start_hook is not None:
            start_hook()

        try:
            while True:
                try:
                    item, slot = q_in.get(timeout=timeout)
                except queue.Empty:
                    return
                if slot < 0:
                    return

                try:
                    values_cache[slot] = sequence[item]
                except Exception as error:
                    _, _, trace = sys.exc_info()
                    trace = tblib.Traceback(trace)
                    tb_str = traceback.format_exc(20)
                    # noinspection PyBroadException
                    try:  # this one may fail if ev is not picklable
                        errors_cache[slot] = error, trace
                    except Exception:
                        errors_cache[slot] = None, tb_str

                    q_out.put_nowait((item, slot, JobStatus.FAILED))

                else:
                    q_out.put_nowait((item, slot, JobStatus.DONE))

        except IOError:
            return  # parent probably died
Пример #2
0
 def _unpack_picked_error(self, pickled_error: bytes) -> Status:
     """Unpacks `pickled_error` into a object of type Status"""
     s = Status()
     exc = pickle.loads(pickled_error)
     s.error_text = traceback.format_exception(*exc)[-1]
     s.tb = json.dumps(tblib.Traceback(exc[2]).to_dict())
     return s
Пример #3
0
def create_return_value(payload):
    """Convenience function that creates a return value that can be
       passed back by a function. The 'payload' should either be
       a dictionary of return data, or it should be an exception.

    """
    try:
        if payload is None:
            return {"status": 0}

        elif isinstance(payload, Exception):
            err = {
                "class": str(payload.__class__.__name__),
                "module": str(payload.__class__.__module__),
                "error": str(payload)
            }

            if payload.__traceback__ is not None:
                import tblib as _tblib
                tb = _tblib.Traceback(payload.__traceback__)
                err["traceback"] = tb.to_dict()

            return {"status": -1, "exception": err}

        elif isinstance(payload, dict):
            return {"status": 0, "return": payload}
        else:
            return {"status": 0, "return": {"result": payload}}

    except Exception as e:
        return {"status": -3, "error": str(e)}
    except:
        return {"status": -4, "error": "unknown"}
Пример #4
0
 def handle(self, record):
     record.msg += ' (message from worker {})'.format(self._worker_id)
     if record.exc_info:
         record.exc_info = (record.exc_info[0], record.exc_info[1],
                            tblib.Traceback(record.exc_info[2]))
     try:
         self._client.call('log', pickle.dumps(record))
     except:
         pass
Пример #5
0
 def wrapper(*args, **kwargs):
     try:
         result = dict(code='success', result=func(*args, **kwargs))
     except:
         logger.exception("Exception in child rpc_result")
         _type, value, _tb = sys.exc_info()
         exc_info = (_type, value, tblib.Traceback(_tb))
         result = dict(code='error', result=exc_info)
     logger.debug("returning {!r} for".format(result))
     return pickle.dumps(result)
Пример #6
0
 def log(self, log_record):
     try:
         record = pickle.loads(log_record)
         if record.exc_info:
             record.exc_info = (record.exc_info[0], record.exc_info[1],
                                tblib.Traceback(
                                    record.exc_info[2].as_traceback()))
         logging.getLogger(record.name).handle(record)
     except:
         pass
Пример #7
0
def exception_to_safe_exception(e):
    """Convert the passed exception to a "safe" exception - this is one
       that can be copied because it does not hold references to any
       local data
    """
    if not issubclass(e.__class__, Exception):
        return TypeError(str(e))

    import tblib as _tblib
    tb = _tblib.Traceback(e.__traceback__)
    e.__traceback__ = tb.as_traceback()

    return e
Пример #8
0
    def target(pid, func, value_slots, error_slots, job_queue, done_queue,
               timeout, start_hook):
        logger = get_logger(__name__)

        seterr(evaluation='passthrough')
        if start_hook is not None:
            start_hook()

        logger.debug("worker %d: starting", pid)

        # make 1D bytes views of the buffer slots
        while True:
            try:  # acquire job
                slot = job_queue.get(timeout=timeout)

            except queue.Empty:  # or go to sleep
                try:  # notify parent
                    done_queue.put((-pid - 1, 0))
                finally:
                    logger.debug("worker %d: timeout, exiting", pid)
                    return

            except IOError:  # parent probably died
                logger.debug("worker %d: parent died, exiting", pid)
                return

            if slot < 0:
                logger.debug("worker %d: clean termination", pid)
                return

            try:  # generate and store value
                value_slots[slot] = func()
                job_status = JobStatus.DONE

            except Exception as error:  # save error informations if any
                try:
                    trace_dump = tblib.Traceback(sys.exc_info()[2])
                    error_slots[slot] = error, trace_dump
                except Exception:
                    error_slots[slot] = None, None

                job_status = JobStatus.FAILED

            try:  # notify about job termination
                done_queue.put((slot, job_status))
            except IOError:  # parent process died unexpectedly
                logger.debug("worker %d: parent died, exiting", pid)
                return
Пример #9
0
async def worker(
    consumer_name: str,
    redis_url: str,
    worker_id: Optional[str] = None,
    stopped_event: Optional[Event] = None,
):

    worker_id = worker_id or uuid4()
    log = logging.getLogger(f"pyuubin.worker.{worker_id}")
    db = RedisDb()
    await db.connect(redis_url)
    stopped_event = stopped_event or Event()

    log.info(f"Starting worker: {worker_id} for `{consumer_name}`.")

    async with db.mail_consumer(consumer_name) as consumer:
        async for email in consumer.mail_queue(stopped_event):

            templates = Templates(await db.load_templates())
            log.info("Received an email and sending it.")
            try:
                await send_mail(email, templates)
                log.info("Email sent.")
            except CannotSendMessages as e:
                await db.add_mail(email)
                log.error("Cannot send messages.")
                if (log.getEffectiveLevel() == logging.DEBUG
                    ):  # pragma: no cover
                    log.exception(e)
                stopped_event.set()
            except (FailedToSendMessage, Exception) as e:
                et, ev, tb = sys.exc_info()
                await consumer.report_failed_mail(
                    email, traceback=tblib.Traceback(tb).to_dict())
                log.error(f"Failed to send message: {e}")
                log.exception(e)
            finally:
                await consumer.ack_mail(email)

    log.info("Shutting down the worker.")
    await db.close()
Пример #10
0
    def target(sequence, buffers, errors_cache, q_in, q_out, timeout,
               start_hook):
        signal.signal(signal.SIGINT,
                      signal.SIG_IGN)  # let parent handle signals

        if start_hook is not None:
            start_hook()

        buffers = tuple(
            np.reshape(np.frombuffer(b, t), (-1, ) + s) for b, t, s in buffers)

        try:
            while True:
                try:
                    item, slot = q_in.get(timeout=timeout)
                except queue.Empty:
                    return
                if slot < 0:
                    return

                try:
                    for field, buffer in zip(sequence[item], buffers):
                        buffer[slot] = field
                except Exception as error:
                    _, _, trace = sys.exc_info()
                    trace = tblib.Traceback(trace)
                    tb_str = traceback.format_exc(20)
                    # noinspection PyBroadException
                    try:  # this one may fail if ev is not picklable
                        errors_cache[slot] = error, trace
                    except Exception:
                        errors_cache[slot] = None, tb_str

                    q_out.put_nowait((item, slot, JobStatus.FAILED))

                else:
                    q_out.put_nowait((item, slot, JobStatus.DONE))

        except IOError:
            return  # parent probably died
Пример #11
0
 def _unpack_picked_error(self, pickled_error: bytes) -> Tuple[str, str]:
     """Unpacks `pickled_error` into and error `message` and `tb` string."""
     exc = pickle.loads(pickled_error)
     message = traceback.format_exception(*exc)[-1]
     tb = json.dumps(tblib.Traceback(exc[2]).to_dict())
     return message, tb
Пример #12
0
    def post(self, rosname):

        # fail early if no pyros client
        if self.node_client is None:
            self.logger.warn('404 : %s', rosname)
            return make_response('', 404)

        try:
            rosname = '/' + rosname
            #self.logger.debug('POST')
            length = int(request.environ['CONTENT_LENGTH'])
            use_ros = (
                'CONTENT_TYPE' in request.environ and ROS_MSG_MIMETYPE
                == request.environ['CONTENT_TYPE'].split(';')[0].strip())

            services = self.node_client.services()
            topics = self.node_client.topics()
            params = self.node_client.params()

            if rosname in services:
                mode = 'service'
                service = services[rosname]
            elif rosname in topics:
                mode = 'topic'
                topic = topics[rosname]
            elif rosname in params:
                mode = 'param'
                param = params[rosname]
            else:
                self.logger.warn('404 : %s', rosname)
                return make_response('', 404)

            # we are now sending via the client node, which will convert the
            # received dict into the correct message type for the service (or
            # break, if it's wrong.)

            # Trying to parse the input
            try:
                input_data = request.environ['wsgi.input'].read(length)
                input_data = simplejson.loads(input_data or "{}")
                input_data.pop('_format', None)
                #TODO : We get the message structure via the topic, can we already use it for checking before calling rospy ?
            except ValueError as exc_value:
                raise WrongMessageFormat(
                    message="Your request payload was incorrect: {exc_value}".
                    format(exc_value=exc_value),
                    traceback=tblib.Traceback(sys.exc_info()[2]).to_dict())

            # input_msg = input_msg_type() # was topic.rostype but we dont have it here ( cant serialize and transfer easily )
            # self.logger.debug('input_msg:%r', input_msg)
            # if use_ros:
            #     input_msg.deserialize(input_data)
            # else:
            #     input_data = json.loads(input_data)
            #     input_data.pop('_format', None)
            #     msgconv.populate_instance(input_data, input_msg)

            response = None
            try:
                if mode == 'service':
                    self.logger.debug('calling service %s with msg : %s',
                                      service.get('name', None), input_data)
                    ret_msg = self.node_client.service_call(
                        rosname, input_data)

                    if use_ros:
                        content_type = ROS_MSG_MIMETYPE
                        output_data = StringIO()
                        ret_msg.serialize(output_data)
                        output_data = output_data.getvalue()
                    elif ret_msg:
                        output_data = ret_msg  # the returned message is already converted from ros format by the client
                        output_data['_format'] = 'ros'
                        output_data = simplejson.dumps(output_data,
                                                       ignore_nan=True)
                        content_type = 'application/json'
                    else:
                        output_data = "{}"
                        content_type = 'application/json'

                    response = make_response(output_data, 200)
                    response.mimetype = content_type

                elif mode == 'topic':
                    self.logger.debug('publishing \n%s to topic %s',
                                      input_data, topic.get('name', None))
                    self.node_client.topic_inject(rosname, input_data)
                    response = make_response('{}', 200)
                    response.mimetype = 'application/json'
                elif mode == 'param':
                    self.logger.debug('setting \n%s param %s', input_data,
                                      param.get('name', None))
                    self.node_client.param_set(rosname, input_data)
                    response = make_response('{}', 200)
                    response.mimetype = 'application/json'
                return response

            # converting pyros exceptions to proper rostful exceptions
            # except (InvalidMessageException, NonexistentFieldException, FieldTypeMismatchException) as exc_value:
            #     raise WrongMessageFormat(
            #         message=str(exc_value.message),
            #         traceback=tblib.Traceback(sys.exc_info()[2]).to_dict()
            #     )
            except PyrosServiceTimeout as exc_value:
                raise ServiceTimeout(message=str(exc_value.message),
                                     traceback=tblib.Traceback(
                                         sys.exc_info()[2]).to_dict())
            except PyrosServiceNotFound as exc_value:
                raise ServiceNotFound(message=str(exc_value.message),
                                      traceback=tblib.Traceback(
                                          sys.exc_info()[2]).to_dict())

        # returning local exceptions
        except WrongMessageFormat as wmf:
            self.logger.error(
                'Wrong message format! => {status} \n{exc}'.format(
                    status=wmf.status_code, exc=wmf.message))
            return make_response(
                simplejson.dumps(wmf.to_dict(), ignore_nan=True),
                wmf.status_code)

        except ServiceTimeout as st:
            self.logger.error('Service Timeout! => {status} \n{exc}'.format(
                status=st.status_code, exc=st.message))
            return make_response(
                simplejson.dumps(st.to_dict(), ignore_nan=True),
                st.status_code)

        except ServiceNotFound as snf:
            self.logger.error('Service Not Found! => {status} \n{exc}'.format(
                status=snf.status_code, exc=snf.message))
            return make_response(
                simplejson.dumps(snf.to_dict(), ignore_nan=True),
                snf.status_code)

        # Generic way to return Exceptions we don't know how to handle
        # But we can do a tiny bit better if it s a PyrosException
        except Exception as exc_value:
            exc_type, exc_value, tb = sys.exc_info()
            tb = tblib.Traceback(tb)
            exc_dict = {
                'exc_type':
                str(exc_type),
                # TODO : it would be nice if pyros exception wouldnt need such a check...
                'exc_value':
                str(exc_value.message)
                if isinstance(exc_value, PyrosException) else str(exc_value),
                'traceback':
                tb.to_dict()
            }
            self.logger.error(
                'An exception occurred! => 500 \n{exc}'.format(exc=exc_dict))
            return make_response(simplejson.dumps(exc_dict, ignore_nan=True),
                                 500)
Пример #13
0
def _build_and_evaluate_design(cfg):
    """
    Build the "current" design proposal and evaluate its performance.

    """
    # We want to treat the build process as an
    # integrated part of the product, so as soon
    # as we know which system configuration is
    # to be built, we launch a new (sub)process
    # so that the remainder of the build process
    # can be taken from that system configuration.
    #

    # We define a pickle file that we use to record
    # the result of the build and make sure that
    # any old files with the same name have been
    # removed from the temporary directory.
    #
    dirpath_branch_tmp = cfg['paths']['dirpath_branch_tmp']
    filepath_result = os.path.join(dirpath_branch_tmp, 'result.pickle')
    cfg['paths']['filepath_result'] = filepath_result
    if os.path.isfile(filepath_result):
        os.remove(filepath_result)

    # We pickle the configuration and base64 encode
    # it so we can send it as a command-line parameter
    # to the build process.
    #
    pickled_cfg = base64.b64encode(
        pickle.dumps(cfg, protocol=da.constants.PICKLE_PROTOCOL))

    # Call the build in a subprocess.
    #
    # NOTE: We communicate with the subprocess
    #       using pickled data -- so there are
    #       potential security concerns here and
    #       we need to be careful to keep this
    #       data secure.
    #
    dirpath_isolated_src = cfg['paths']['dirpath_isolated_src']
    da.lwc.run.python3(['-m', 'da.metabuild', pickled_cfg],
                       dirpath_lwc_root=dirpath_isolated_src)

    # We expect the subprocess to pickle the
    # results (Exception or success) in our
    # defined results file.
    #
    if not os.path.isfile(filepath_result):
        raise RuntimeError(
            'Could not find result file from subsidiary build process. '
            'It seems to have terminated unexpectedly.')
    with open(filepath_result, 'rb', buffering=1) as file_result:
        result = pickle.load(file_result)

    # Examine output and raise exception if required.
    if result == da.constants.BUILD_COMPLETED:
        return result
    else:
        (_, exception_value, trace_back) = result

        # We want to be able to open our text editor
        # or IDE at the location where an exception
        # was thrown - but we don't want to open
        # the file *inside* the isolation dir, as
        # our changes will simply be overwritten
        # on the next build. Instead, we want to
        # open the *real* source file in our local
        # working copy.
        #
        # To do this, we re-write the contents of
        # the traceback data structure so that
        # references to the isolated source
        # directory get replaced by references
        # to the "outer" local working copy
        # directory.
        #
        dirpath_outer_lwc_root = cfg['paths']['dirpath_lwc_root']
        trace_back_dict = tblib.Traceback(trace_back).to_dict()
        for obj in da.util.walkobj(trace_back_dict,
                                   gen_leaf=False,
                                   gen_nonleaf=True,
                                   gen_path=False,
                                   gen_obj=True):
            if isinstance(obj, collections.Mapping):
                for key in ('co_filename', '__file__'):
                    if key in obj:
                        obj[key] = obj[key].replace(dirpath_isolated_src,
                                                    dirpath_outer_lwc_root)

        raise exception_value.with_traceback(
            tblib.Traceback.from_dict(trace_back_dict).as_traceback())