示例#1
0
                def action(scheduler: abc.SchedulerBase, state: Any = None):
                    s: Optional[Subject[_T]] = None

                    if is_shift:
                        s = Subject()
                        queue.append(s)
                        observer.on_next(add_ref(s, ref_count_disposable))

                    if is_span:
                        s = queue.pop(0)
                        s.on_completed()

                    create_timer()
示例#2
0
class _RxWriter(object):
    success_count = 0
    failed_count = 0
    raise_retry_exception = 0

    def __init__(self) -> None:
        self._subject = Subject()
        self._scheduler = ThreadPoolScheduler(max_workers=1)
        obs = self._subject.pipe(ops.observe_on(self._scheduler))
        self._disposable = obs \
            .pipe(ops.window_with_time_or_count(count=5, timespan=datetime.timedelta(milliseconds=10_000)),
                  ops.flat_map(lambda x: self._window_to_group(x)),
                  ops.map(mapper=lambda x: self._retryable(data=x, delay=self._jitter_delay(jitter_interval=1000))),
                  ops.merge_all()) \
            .subscribe(self._result, self._error, self._on_complete)
        pass

    def close(self):
        self.__del__()

    def __del__(self):
        if self._subject:
            self._subject.on_completed()
            self._subject.dispose()
            self._subject = None

            while not self._disposable.is_disposed:
                time.sleep(0.1)

        if self._disposable:
            self._disposable = None
        pass

    def _window_to_group(self, value):
        return value.pipe(
            ops.to_iterable(),
            ops.map(
                lambda x: rx.from_iterable(x).pipe(ops.group_by(
                    _group_by), ops.map(_group_to_batch), ops.merge_all())),
            ops.merge_all())

    def _retryable(self, data: str, delay: datetime.timedelta):

        return rx.of(data).pipe(
            ops.delay(duetime=delay, scheduler=self._scheduler),
            ops.map(lambda x: self._http(x)),
            ops.catch(handler=lambda exception, source: self._retry_handler(
                exception, source, data)),
        )

    def _http(self, data: str):
        if "gamma" in data:
            print('bad request[{}]: {}'.format(current_thread().name, data))
            raise Exception('unexpected token: {}'.format(data))
            pass

        if "alpha" in data:
            if self.raise_retry_exception < 2:
                self.raise_retry_exception += 1
                print(
                    'server is temporarily unavailable to accept writes[{}]: {}'
                    .format(current_thread().name, data))
                raise Exception(
                    'server is temporarily unavailable to accept writes: {}'.
                    format(data))
            else:
                print("server is OK: {}".format(datetime.datetime.now()))
            pass

        print("http[" + current_thread().name + "]: " + data)
        return _Notification(data=data)

    def write(self, data: str):
        print("write[" + current_thread().name + "]")
        self._subject.on_next(data)
        pass

    def _result(self, data: _Notification):
        print("result[" + current_thread().name + "]: " + str(data))
        if data.exception:
            self.failed_count += 1
        else:
            self.success_count += 1
        pass

    def _error(self, error):
        print(error)

    def _on_complete(self):
        self._disposable.dispose()
        print("on complete")

    def _jitter_delay(self, jitter_interval=0):
        _jitter = datetime.timedelta(milliseconds=random() * jitter_interval)
        print('jitter: {}'.format(_jitter))
        return _jitter

    def _retry_handler(self, exception, source, data):
        print('retry_handler: {}, source: {}'.format(exception, source))

        if "server is temporarily" in str(exception):
            print("RETRY!!!: {}".format(datetime.datetime.now()))
            return self._retryable(data, delay=datetime.timedelta(seconds=2))

        notification = _Notification(exception=exception, data=data)

        return rx.just(notification)