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

io.camunda.operate.store.elasticsearch.ElasticsearchTaskStore Maven / Gradle / Ivy

/*
 * 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.operate.store.elasticsearch;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.camunda.operate.conditions.ElasticsearchCondition;
import io.camunda.operate.exceptions.OperateRuntimeException;
import io.camunda.operate.store.TaskStore;
import io.camunda.operate.store.elasticsearch.dao.response.TaskResponse;
import io.camunda.operate.util.Either;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.http.client.methods.HttpGet;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.tasks.TaskInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;

@Conditional(ElasticsearchCondition.class)
@Component
public class ElasticsearchTaskStore implements TaskStore {

  public static final String ID = "id";
  public static final String REASON = "reason";
  public static final String CAUSE = "cause";
  public static final String CREATED = "created";
  public static final String TASK_ACTION_INDICES_REINDEX = "indices:data/write/reindex";
  public static final String DESCRIPTION_PREFIX_FROM_INDEX = "reindex from [";
  public static final String DESCRIPTION_PREFIX_TO_INDEX = "to [";
  private static final String TASKS_ENDPOINT = "_tasks";
  private static final Logger LOGGER = LoggerFactory.getLogger(ElasticsearchTaskStore.class);
  @Autowired private RestHighLevelClient esClient;

  @Autowired
  @Qualifier("operateObjectMapper")
  private ObjectMapper objectMapper;

  public Either getTaskResponse(final String taskId) {
    try {
      final var request = new Request(HttpGet.METHOD_NAME, "/" + TASKS_ENDPOINT + "/" + taskId);
      final var response = esClient.getLowLevelClient().performRequest(request);
      final var taskResponse =
          objectMapper.readValue(response.getEntity().getContent(), TaskResponse.class);
      return Either.right(taskResponse);
    } catch (IOException e) {
      return Either.left(e);
    }
  }

  public void checkForErrorsOrFailures(final TaskResponse taskResponse) {
    checkForErrors(taskResponse);
    checkForFailures(taskResponse);
  }

  public List getRunningReindexTasksIdsFor(final String fromIndex, final String toIndex)
      throws IOException {
    if (fromIndex == null || toIndex == null) {
      return List.of();
    }
    return getReindexTasks().stream()
        .filter(
            taskInfo ->
                descriptionContainsReindexFromTo(taskInfo.getDescription(), fromIndex, toIndex))
        .map(this::toTaskId)
        .toList();
  }

  private String toTaskId(TaskInfo taskInfo) {
    return String.format("%s:%s", taskInfo.getTaskId().getNodeId(), taskInfo.getTaskId().getId());
  }

  private boolean descriptionContainsReindexFromTo(
      final String description, final String fromIndex, final String toIndex) {
    return description != null
        && description.contains(DESCRIPTION_PREFIX_FROM_INDEX + fromIndex)
        && description.contains(DESCRIPTION_PREFIX_TO_INDEX + toIndex);
  }

  private List getReindexTasks() throws IOException {
    final var response =
        esClient
            .tasks()
            .list(
                new ListTasksRequest().setActions(TASK_ACTION_INDICES_REINDEX).setDetailed(true),
                RequestOptions.DEFAULT);
    return response.getTasks();
  }

  private void checkForErrors(final TaskResponse taskResponse) {
    if (taskResponse != null && taskResponse.getError() != null) {
      final var error = taskResponse.getError();
      LOGGER.error("Task status contains error: " + error);
      throw new OperateRuntimeException(error.getReason());
    }
  }

  private void checkForFailures(final TaskResponse taskStatus) {
    if (taskStatus != null && taskStatus.getResponseDetails() != null) {
      final var taskResponse = taskStatus.getResponseDetails();
      final var failures = taskResponse.getFailures();
      if (!failures.isEmpty()) {
        final Map failure = (Map) failures.get(0);
        final Map cause = (Map) failure.get(CAUSE);
        throw new OperateRuntimeException(cause.get(REASON));
      }
    }
  }

  public boolean needsToPollAgain(final Optional maybeTaskResponse) {
    return maybeTaskResponse.isEmpty()
        || maybeTaskResponse.filter(tr -> !tr.isCompleted()).isPresent();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy