@Override public long now(TimeUnit unit) { return cached.now(unit); }
@Override public boolean isExpired() { long done = this.done; return done != NOT_DONE && scheduler.now(TimeUnit.MILLISECONDS) - maxAge > done; }
@Override public void onError(Throwable ex) { done = scheduler.now(TimeUnit.MILLISECONDS); error = ex; }
@Override public void onComplete() { done = scheduler.now(TimeUnit.MILLISECONDS); }
Tuple2<Long, T> snapshot(T data){ long now = scheduler.now(TimeUnit.MILLISECONDS); long last = lastTime; lastTime = now; long delta = now - last; return Tuples.of(delta, data); }
/** * If this {@link Mono} is valued, emit a {@link reactor.util.function.Tuple2} pair of * T1 the current clock time in millis (as a {@link Long} measured by the * provided {@link Scheduler}) and T2 the emitted data (as a {@code T}). * * <p> * <img class="marble" src="doc-files/marbles/timestampForMono.svg" alt=""> * * @param scheduler a {@link Scheduler} instance to read time from * @return a timestamped {@link Mono} */ public final Mono<Tuple2<Long, T>> timestamp(Scheduler scheduler) { Objects.requireNonNull(scheduler, "scheduler"); return map(d -> Tuples.of(scheduler.now(TimeUnit.MILLISECONDS), d)); }
/** * Emit a {@link reactor.util.function.Tuple2} pair of T1 the current clock time in * millis (as a {@link Long} measured by the provided {@link Scheduler}) and T2 * the emitted data (as a {@code T}), for each item from this {@link Flux}. * * <p> * <img class="marble" src="doc-files/marbles/timestampForFlux.svg" alt=""> * * @param scheduler the {@link Scheduler} to read time from * @return a timestamped {@link Flux} */ public final Flux<Tuple2<Long, T>> timestamp(Scheduler scheduler) { Objects.requireNonNull(scheduler, "scheduler"); return map(d -> Tuples.of(scheduler.now(TimeUnit.MILLISECONDS), d)); }
@Override public void onSubscribe(Subscription s) { if (Operators.validate(this.s, s)) { lastTime = scheduler.now(TimeUnit.MILLISECONDS); this.s = s; actual.onSubscribe(this); } }
@SuppressWarnings("unchecked") TimedNode<T> latestHead(ReplaySubscription<T> rs) { long now = scheduler.now(TimeUnit.MILLISECONDS) - maxAge; TimedNode<T> h = (TimedNode<T>) rs.node(); if (h == null) { h = head; } TimedNode<T> n; while ((n = h.get()) != null) { if (n.time > now) { break; } h = n; } return h; }
@Override @Nullable public T poll(ReplaySubscription<T> rs) { TimedNode<T> node = latestHead(rs); TimedNode<T> next; long now = scheduler.now(TimeUnit.MILLISECONDS) - maxAge; while ((next = node.get()) != null) { if (next.time > now) { node = next; break; } node = next; } if (next == null) { return null; } rs.node(next); return node.value; }
@Test public void monoRetryRandomBackoff_noRandom() { AtomicInteger errorCount = new AtomicInteger(); Exception exception = new IOException("boom retry"); List<Long> elapsedList = new ArrayList<>(); StepVerifier.withVirtualTime(() -> Mono.error(exception) .doOnError(e -> { errorCount.incrementAndGet(); elapsedList.add(Schedulers.parallel().now(TimeUnit.MILLISECONDS)); }) .retryBackoff(4, Duration.ofMillis(100), Duration.ofMillis(2000), 0d) ) .thenAwait(Duration.ofMinutes(1)) //ensure whatever the jittered delay that we have time to fit 4 retries .expectErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Retries exhausted: 4/4") .hasCause(exception)) .verify(Duration.ofSeconds(1)); //vts test shouldn't even take that long assertThat(errorCount).hasValue(5); assertThat(elapsedList.get(0)).isEqualTo(0L); assertThat(elapsedList.get(1) - elapsedList.get(0)).isEqualTo(100); assertThat(elapsedList.get(2) - elapsedList.get(1)).isEqualTo(200); assertThat(elapsedList.get(3) - elapsedList.get(2)).isEqualTo(400); assertThat(elapsedList.get(4) - elapsedList.get(3)).isEqualTo(800); }
empty = ts == null; if (!empty) { if (ts <= ttlScheduler.now(TimeUnit.MILLISECONDS) - ttl.toMillis()) { this.poll(); evicted = (T) this.poll();
@Test public void monoRetryRandomBackoff_minBackoffFloor() { for (int i = 0; i < 50; i++) { AtomicInteger errorCount = new AtomicInteger(); Exception exception = new IOException("boom retry loop #" + i); List<Long> elapsedList = new ArrayList<>(); StepVerifier.withVirtualTime(() -> Mono.error(exception) .doOnError(e -> { errorCount.incrementAndGet(); elapsedList.add(Schedulers.parallel().now(TimeUnit.MILLISECONDS)); }) .retryBackoff(1, Duration.ofMillis(100), Duration.ofMillis(2000), 0.9) ) .thenAwait(Duration.ofMinutes(1)) //ensure whatever the jittered delay that we have time to fit 4 retries .expectErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Retries exhausted: 1/1") .hasCause(exception)) .verify(Duration.ofSeconds(1)); //vts test shouldn't even take that long assertThat(errorCount).hasValue(2); assertThat(elapsedList).hasSize(2); assertThat(elapsedList.get(0)).isEqualTo(0L); assertThat(elapsedList.get(1) - elapsedList.get(0)) .isGreaterThanOrEqualTo(100) //min backoff .isCloseTo(100, Percentage.withPercentage(90)); } }
.doOnError(e -> { errorCount.incrementAndGet(); elapsedList.add(Schedulers.parallel().now(TimeUnit.MILLISECONDS)); }) .retryBackoff(4, Duration.ofMillis(100), Duration.ofMillis(220), 0.9)
.doOnError(e -> { errorCount.incrementAndGet(); elapsedList.add(Schedulers.parallel().now(TimeUnit.MILLISECONDS)); }) .retryBackoff(4, Duration.ofMillis(100))
.doOnError(e -> { errorCount.incrementAndGet(); elapsedList.add(Schedulers.parallel().now(TimeUnit.MILLISECONDS)); }) .retryBackoff(4, Duration.ofMillis(100), Duration.ofMillis(2000), 0.1)
.doOnError(e -> { errorCount.incrementAndGet(); elapsedList.add(Schedulers.parallel().now(TimeUnit.MILLISECONDS)); }) .retryBackoff(4, Duration.ofMillis(100), Duration.ofMillis(2000))
@SuppressWarnings("unchecked") @Override public void onNext(T t) { T evicted = null; synchronized (this) { if (this.size() == bufferSizeDouble) { this.poll(); evicted = (T) this.poll(); } this.offer(ttlScheduler.now(TimeUnit.MILLISECONDS)); this.offer(t); } evict(evicted); try { worker.schedule(this, ttl.toMillis(), TimeUnit.MILLISECONDS); } catch (RejectedExecutionException re) { done = true; error = Operators.onRejectedExecution(re, this, null, t, actual.currentContext()); } drain(); }
if (done == NOT_DONE) { long limit = scheduler.now(TimeUnit.MILLISECONDS) - maxAge; TimedNode<T> next = node; while (next != null) {