All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rabbitmq.stream.impl.ScheduledExecutorServiceWrapper Maven / Gradle / Ivy

Go to download

The RabbitMQ Stream Java client library allows Java applications to interface with RabbitMQ Stream.

There is a newer version: 0.20.0
Show newest version
// Copyright (c) 2022 VMware, Inc. or its affiliates.  All rights reserved.
//
// This software, the RabbitMQ Stream Java client library, is dual-licensed under the
// Mozilla Public License 2.0 ("MPL"), and the Apache License version 2 ("ASL").
// For the MPL, please see LICENSE-MPL-RabbitMQ. For the ASL,
// please see LICENSE-APACHE2.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied. See the LICENSE file for specific language governing
// rights and limitations of this software.
//
// If you have any questions regarding licensing, please contact us at
// [email protected].
package com.rabbitmq.stream.impl;

import com.rabbitmq.stream.impl.Utils.NamedThreadFactory;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class ScheduledExecutorServiceWrapper implements ScheduledExecutorService {

  private static final Logger LOGGER =
      LoggerFactory.getLogger(ScheduledExecutorServiceWrapper.class);
  private final ScheduledExecutorService delegate;
  private final Set tasks = ConcurrentHashMap.newKeySet();
  private final ScheduledExecutorService scheduler =
      Executors.newSingleThreadScheduledExecutor(
          new NamedThreadFactory("rabbitmq-stream-scheduled-executor-service-wrapper-"));

  ScheduledExecutorServiceWrapper(ScheduledExecutorService delegate) {
    this.delegate = delegate;
    Duration period = Duration.ofSeconds(10);
    this.scheduler.scheduleAtFixedRate(
        () -> {
          LOGGER.debug("Background scheduled task check, {} task(s) submitted", this.tasks.size());
          try {
            long now = System.nanoTime();
            Duration warningTimeout = Duration.ofSeconds(60);
            int cleanedCount = 0;
            Iterator iterator = this.tasks.iterator();
            while (iterator.hasNext()) {
              Task task = iterator.next();
              if (task.isCompleted()) {
                iterator.remove();
                cleanedCount++;
              } else {
                Duration elapsed = task.elapsedTime(now);
                if (elapsed.compareTo(warningTimeout) > 0) {
                  LOGGER.debug(
                      "Warning: task {} has been running for {} second(s)",
                      task.description,
                      elapsed.getSeconds());
                }
              }
            }
            LOGGER.debug("{} completed task(s) cleaned", cleanedCount);
          } catch (Exception e) {
            LOGGER.debug("Error during background scheduled task check", e.getMessage());
          }
        },
        period.toMillis(),
        period.toMillis(),
        TimeUnit.MILLISECONDS);
  }

  private void task(Runnable command, Future future) {
    task(command.toString(), future);
  }

  private void task(Callable callable, Future future) {
    task(callable.toString(), future);
  }

  private void task(String description, Future future) {
    this.tasks.add(new Task(description, future));
  }

  @Override
  public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) {
    ScheduledFuture future = this.delegate.schedule(command, delay, unit);
    task(command, future);
    return future;
  }

  @Override
  public  ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) {
    ScheduledFuture future = this.delegate.schedule(callable, delay, unit);
    task(callable, future);
    return future;
  }

  @Override
  public ScheduledFuture scheduleAtFixedRate(
      Runnable command, long initialDelay, long period, TimeUnit unit) {
    // we don't track these, because they are expected to run for a long time
    LOGGER.debug("Registering scheduled at fixed rate task '{}'", command.toString());
    return this.delegate.scheduleAtFixedRate(command, initialDelay, period, unit);
  }

  @Override
  public ScheduledFuture scheduleWithFixedDelay(
      Runnable command, long initialDelay, long delay, TimeUnit unit) {
    // we don't track these, because they are expected to run for a long time
    LOGGER.debug("Registering scheduled with fixed delay task '%s'", command.toString());
    return this.delegate.scheduleWithFixedDelay(command, initialDelay, delay, unit);
  }

  @Override
  public void shutdown() {
    this.delegate.shutdown();
  }

  @Override
  public List shutdownNow() {
    return this.delegate.shutdownNow();
  }

  @Override
  public boolean isShutdown() {
    return this.delegate.isShutdown();
  }

  @Override
  public boolean isTerminated() {
    return this.delegate.isTerminated();
  }

  @Override
  public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
    return this.delegate.awaitTermination(timeout, unit);
  }

  @Override
  public  Future submit(Callable task) {
    Future future = this.delegate.submit(task);
    task(task, future);
    return future;
  }

  @Override
  public  Future submit(Runnable task, T result) {
    Future future = this.delegate.submit(task, result);
    task(task, future);
    return future;
  }

  @Override
  public Future submit(Runnable task) {
    Future future = this.delegate.submit(task);
    task(task, future);
    return future;
  }

  @Override
  public  List> invokeAll(Collection> tasks)
      throws InterruptedException {
    List> taskList = new ArrayList<>(tasks);
    List> futures = this.delegate.invokeAll(taskList);
    for (int i = 0; i < taskList.size(); i++) {
      task(taskList.get(i), futures.get(i));
    }
    return futures;
  }

  @Override
  public  List> invokeAll(
      Collection> tasks, long timeout, TimeUnit unit)
      throws InterruptedException {
    List> taskList = new ArrayList<>(tasks);
    List> futures = this.delegate.invokeAll(taskList, timeout, unit);
    for (int i = 0; i < taskList.size(); i++) {
      task(taskList.get(i), futures.get(i));
    }
    return futures;
  }

  @Override
  public  T invokeAny(Collection> tasks) {
    throw new UnsupportedOperationException();
  }

  @Override
  public  T invokeAny(Collection> tasks, long timeout, TimeUnit unit) {
    throw new UnsupportedOperationException();
  }

  @Override
  public void execute(Runnable command) {
    Callable callable =
        () -> {
          command.run();
          return null;
        };
    Future future = this.delegate.submit(callable);
    task(command, future);
  }

  static class Task {

    private final Future future;
    private final String description;
    private final long start;

    Task(String description, Future future) {
      this.description = description;
      this.future = future;
      this.start = System.nanoTime();
    }

    boolean isCompleted() {
      return this.future.isDone();
    }

    Duration elapsedTime(long now) {
      if (now - start < 0) {
        return Duration.ZERO;
      } else {
        return Duration.ofNanos(now - start);
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy