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

io.camunda.exporter.tasks.BackgroundTaskManager Maven / Gradle / Ivy

There is a newer version: 8.7.0-alpha2
Show newest version
/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. See the NOTICE file distributed
 * with this work for additional information regarding copyright ownership.
 * Licensed under the Camunda License 1.0. You may not use this file
 * except in compliance with the Camunda License 1.0.
 */
package io.camunda.exporter.tasks;

import io.camunda.exporter.tasks.archiver.ArchiverRepository;
import io.camunda.zeebe.util.CloseableSilently;
import io.camunda.zeebe.util.VisibleForTesting;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import javax.annotation.WillCloseWhenClosed;
import org.agrona.CloseHelper;
import org.slf4j.Logger;

public final class BackgroundTaskManager implements CloseableSilently {
  private final int partitionId;
  private final ArchiverRepository repository;
  private final Logger logger;
  private final ScheduledThreadPoolExecutor executor;
  private final List tasks;

  private int submittedTasks = 0;

  @VisibleForTesting
  BackgroundTaskManager(
      final int partitionId,
      final @WillCloseWhenClosed ArchiverRepository repository,
      final Logger logger,
      final @WillCloseWhenClosed ScheduledThreadPoolExecutor executor,
      final List tasks) {
    this.partitionId = partitionId;
    this.repository = Objects.requireNonNull(repository, "must specify a repository");
    this.logger = Objects.requireNonNull(logger, "must specify a logger");
    this.executor = Objects.requireNonNull(executor, "must specify an executor");
    this.tasks = Objects.requireNonNull(tasks, "must specify tasks");
  }

  @Override
  public void close() {
    // Close executor first before anything else; this will ensure any callbacks are not triggered
    // in case we close any underlying resource (e.g. repository) and would want to perform
    // unnecessary error handling in any of these callbacks
    //
    // avoid calling executor.close, which will await 1d (!) until termination
    // we also don't need to wait for the jobs to fully finish, as we should be able to handle
    // partial jobs (e.g. node crash/restart)
    executor.shutdownNow();
    CloseHelper.close(
        error ->
            logger.warn("Failed to close archiver repository for partition {}", partitionId, error),
        repository);
  }

  public void start() {
    // make sure this is retry-able, as this is called in the exporter's open phase, which can be
    // retried; in this case, we don't want to resubmit previously submitted tasks
    final var unsubmittedTasks = tasks.size() - submittedTasks;
    if (unsubmittedTasks == 0) {
      return;
    }

    logger.debug(
        "Starting {} background tasks (with {} previously submitted tasks out of {} tasks)",
        unsubmittedTasks,
        submittedTasks,
        tasks.size());
    for (; submittedTasks < tasks.size(); submittedTasks++) {
      final var task = tasks.get(submittedTasks);
      executor.submit(task);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy