1919import com .hivemq .adapter .sdk .api .events .model .Event ;
2020import com .hivemq .configuration .service .InternalConfigurations ;
2121import com .hivemq .edge .modules .api .adapters .ProtocolAdapterPollingSampler ;
22- import org .jetbrains .annotations .NotNull ;
2322import com .hivemq .util .ExceptionUtils ;
2423import com .hivemq .util .NanoTimeProvider ;
24+ import org .jetbrains .annotations .NotNull ;
2525import org .jetbrains .annotations .VisibleForTesting ;
2626import org .slf4j .Logger ;
2727import org .slf4j .LoggerFactory ;
2828
2929import java .util .concurrent .CompletableFuture ;
3030import java .util .concurrent .RejectedExecutionException ;
3131import java .util .concurrent .ScheduledExecutorService ;
32+ import java .util .concurrent .ScheduledFuture ;
3233import java .util .concurrent .ThreadLocalRandom ;
3334import java .util .concurrent .TimeUnit ;
3435import java .util .concurrent .atomic .AtomicBoolean ;
3536import java .util .concurrent .atomic .AtomicInteger ;
37+ import java .util .concurrent .atomic .AtomicReference ;
3638
3739public class PollingTask implements Runnable {
3840
@@ -42,12 +44,11 @@ public class PollingTask implements Runnable {
4244 private final @ NotNull ScheduledExecutorService scheduledExecutorService ;
4345 private final @ NotNull EventService eventService ;
4446 private final @ NotNull NanoTimeProvider nanoTimeProvider ;
45- private final @ NotNull AtomicInteger watchdogErrorCount = new AtomicInteger ();
46- private final @ NotNull AtomicInteger applicationErrorCount = new AtomicInteger ();
47-
47+ private final @ NotNull AtomicInteger watchdogErrorCount ;
48+ private final @ NotNull AtomicInteger applicationErrorCount ;
49+ private final @ NotNull AtomicBoolean continueScheduling ;
50+ private final @ NotNull AtomicReference <ScheduledFuture <?>> currentScheduledFuture ;
4851 private volatile long nanosOfLastPolling ;
49- private final @ NotNull AtomicBoolean continueScheduling = new AtomicBoolean (true );
50-
5152
5253 public PollingTask (
5354 final @ NotNull ProtocolAdapterPollingSampler sampler ,
@@ -58,6 +59,19 @@ public PollingTask(
5859 this .scheduledExecutorService = scheduledExecutorService ;
5960 this .eventService = eventService ;
6061 this .nanoTimeProvider = nanoTimeProvider ;
62+ this .watchdogErrorCount = new AtomicInteger ();
63+ this .applicationErrorCount = new AtomicInteger ();
64+ this .continueScheduling = new AtomicBoolean (true );
65+ this .currentScheduledFuture = new AtomicReference <>();
66+ }
67+
68+ private static long getBackoff (final int errorCount ) {
69+ //-- This will backoff up to a max of about a day (unless the max provided is less)
70+ final long max = InternalConfigurations .ADAPTER_RUNTIME_MAX_APPLICATION_ERROR_BACKOFF .get ();
71+ long f = (long ) (Math .pow (2 , Math .min (errorCount , 20 )) * 100 );
72+ f += ThreadLocalRandom .current ().nextInt (0 , errorCount * 100 );
73+ f = Math .min (f , max );
74+ return f ;
6175 }
6276
6377 @ Override
@@ -90,6 +104,10 @@ public void run() {
90104
91105 public void stopScheduling () {
92106 continueScheduling .set (false );
107+ final ScheduledFuture <?> future = currentScheduledFuture .getAndSet (null );
108+ if (future != null ) {
109+ future .cancel (true );
110+ }
93111 }
94112
95113 private void handleInterruptionException (final @ NotNull Throwable throwable ) {
@@ -99,7 +117,8 @@ private void handleInterruptionException(final @NotNull Throwable throwable) {
99117 final var errorCountTotal = watchdogErrorCount .incrementAndGet ();
100118 final var stopBecauseOfTooManyErrors =
101119 errorCountTotal > InternalConfigurations .ADAPTER_RUNTIME_WATCHDOG_TIMEOUT_ERRORS_BEFORE_INTERRUPT .get ();
102- final var milliSecondsSinceLastPoll = TimeUnit .NANOSECONDS .toMillis (nanoTimeProvider .nanoTime () - nanosOfLastPolling );
120+ final var milliSecondsSinceLastPoll =
121+ TimeUnit .NANOSECONDS .toMillis (nanoTimeProvider .nanoTime () - nanosOfLastPolling );
103122 if (stopBecauseOfTooManyErrors ) {
104123 log .warn (
105124 "Detected bad system process {} in sampler {} - terminating process to maintain health ({}ms runtime)" ,
@@ -121,7 +140,6 @@ private void handleInterruptionException(final @NotNull Throwable throwable) {
121140 }
122141 }
123142
124-
125143 private void handleExceptionDuringPolling (final @ NotNull Throwable throwable ) {
126144 final int errorCountTotal = applicationErrorCount .incrementAndGet ();
127145 final int maxErrorsBeforeRemoval = sampler .getMaxErrorsBeforeRemoval ();
@@ -145,11 +163,12 @@ private void handleExceptionDuringPolling(final @NotNull Throwable throwable) {
145163 notifyOnError (sampler , throwable , false );
146164 // no rescheduling
147165 }
148-
149166 }
150167
151168 private void notifyOnError (
152- final @ NotNull ProtocolAdapterPollingSampler sampler , final @ NotNull Throwable t , final boolean continuing ) {
169+ final @ NotNull ProtocolAdapterPollingSampler sampler ,
170+ final @ NotNull Throwable t ,
171+ final boolean continuing ) {
153172 try {
154173 sampler .error (t , continuing );
155174 } catch (final Throwable samplerError ) {
@@ -178,12 +197,10 @@ private void reschedule(final int errorCountTotal) {
178197 }
179198
180199 final long nonNegativeDelay = Math .max (0 , delayInMillis );
181-
182200 if (errorCountTotal == 0 ) {
183201 schedule (nonNegativeDelay );
184202 } else {
185- final long backoff = getBackoff (errorCountTotal ,
186- InternalConfigurations .ADAPTER_RUNTIME_MAX_APPLICATION_ERROR_BACKOFF .get ());
203+ final long backoff = getBackoff (errorCountTotal );
187204 final long effectiveDelay = Math .max (nonNegativeDelay , backoff );
188205 schedule (effectiveDelay );
189206 }
@@ -193,8 +210,10 @@ private void reschedule(final int errorCountTotal) {
193210 void schedule (final long nonNegativeDelay ) {
194211 if (continueScheduling .get ()) {
195212 try {
196- scheduledExecutorService .schedule (this , nonNegativeDelay , TimeUnit .MILLISECONDS );
197- } catch (final RejectedExecutionException rejectedExecutionException ) {
213+ currentScheduledFuture .set (scheduledExecutorService .schedule (this ,
214+ nonNegativeDelay ,
215+ TimeUnit .MILLISECONDS ));
216+ } catch (final RejectedExecutionException ignored ) {
198217 // ignore. This is fine during shutdown.
199218 }
200219 }
@@ -204,12 +223,4 @@ private void resetErrorStats() {
204223 applicationErrorCount .set (0 );
205224 watchdogErrorCount .set (0 );
206225 }
207-
208- private static long getBackoff (final int errorCount , final long max ) {
209- //-- This will backoff up to a max of about a day (unless the max provided is less)
210- long f = (long ) (Math .pow (2 , Math .min (errorCount , 20 )) * 100 );
211- f += ThreadLocalRandom .current ().nextInt (0 , errorCount * 100 );
212- f = Math .min (f , max );
213- return f ;
214- }
215226}
0 commit comments