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

io.zeebe.gateway.EndpointManager 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 Zeebe Community License 1.0. You may not use this file
 * except in compliance with the Zeebe Community License 1.0.
 */
package io.zeebe.gateway;

import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.zeebe.gateway.ResponseMapper.BrokerResponseMapper;
import io.zeebe.gateway.grpc.ServerStreamObserver;
import io.zeebe.gateway.impl.broker.BrokerClient;
import io.zeebe.gateway.impl.broker.RequestRetryHandler;
import io.zeebe.gateway.impl.broker.cluster.BrokerClusterState;
import io.zeebe.gateway.impl.broker.cluster.BrokerTopologyManager;
import io.zeebe.gateway.impl.broker.request.BrokerRequest;
import io.zeebe.gateway.impl.job.ActivateJobsHandler;
import io.zeebe.gateway.protocol.GatewayOuterClass.ActivateJobsRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.ActivateJobsResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.BrokerInfo;
import io.zeebe.gateway.protocol.GatewayOuterClass.BrokerInfo.Builder;
import io.zeebe.gateway.protocol.GatewayOuterClass.CancelWorkflowInstanceRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.CancelWorkflowInstanceResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.CompleteJobRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.CompleteJobResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.CreateWorkflowInstanceRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.CreateWorkflowInstanceResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.CreateWorkflowInstanceWithResultRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.CreateWorkflowInstanceWithResultResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.DeployWorkflowRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.DeployWorkflowResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.FailJobRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.FailJobResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.Partition;
import io.zeebe.gateway.protocol.GatewayOuterClass.Partition.PartitionBrokerHealth;
import io.zeebe.gateway.protocol.GatewayOuterClass.Partition.PartitionBrokerRole;
import io.zeebe.gateway.protocol.GatewayOuterClass.PublishMessageRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.PublishMessageResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.ResolveIncidentRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.ResolveIncidentResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.SetVariablesRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.SetVariablesResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.ThrowErrorRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.ThrowErrorResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.TopologyRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.TopologyResponse;
import io.zeebe.gateway.protocol.GatewayOuterClass.UpdateJobRetriesRequest;
import io.zeebe.gateway.protocol.GatewayOuterClass.UpdateJobRetriesResponse;
import io.zeebe.util.VersionUtil;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public final class EndpointManager {

  private final BrokerClient brokerClient;
  private final BrokerTopologyManager topologyManager;
  private final ActivateJobsHandler activateJobsHandler;
  private final RequestRetryHandler requestRetryHandler;

  public EndpointManager(
      final BrokerClient brokerClient, final ActivateJobsHandler activateJobsHandler) {
    this.brokerClient = brokerClient;
    topologyManager = brokerClient.getTopologyManager();
    this.activateJobsHandler = activateJobsHandler;
    requestRetryHandler = new RequestRetryHandler(brokerClient, topologyManager);
  }

  private void addBrokerInfo(
      final Builder brokerInfo, final Integer brokerId, final BrokerClusterState topology) {
    final String[] addressParts = topology.getBrokerAddress(brokerId).split(":");

    brokerInfo
        .setNodeId(brokerId)
        .setHost(addressParts[0])
        .setPort(Integer.parseInt(addressParts[1]))
        .setVersion(topology.getBrokerVersion(brokerId));
  }

  private void addPartitionInfoToBrokerInfo(
      final Builder brokerInfo, final Integer brokerId, final BrokerClusterState topology) {
    topology
        .getPartitions()
        .forEach(
            partitionId -> {
              final Partition.Builder partitionBuilder = Partition.newBuilder();
              partitionBuilder.setPartitionId(partitionId);

              if (topology.getLeaderForPartition(partitionId) == brokerId) {
                partitionBuilder.setRole(PartitionBrokerRole.LEADER);
              } else {
                final List followersForPartition =
                    topology.getFollowersForPartition(partitionId);

                if (followersForPartition != null && followersForPartition.contains(brokerId)) {
                  partitionBuilder.setRole(PartitionBrokerRole.FOLLOWER);
                } else {
                  return;
                }
              }
              if (topology.isPartitionHealthy(brokerId, partitionId)) {
                partitionBuilder.setHealth(PartitionBrokerHealth.HEALTHY);
              } else {
                partitionBuilder.setHealth(PartitionBrokerHealth.UNHEALTHY);
              }
              brokerInfo.addPartitions(partitionBuilder);
            });
  }

  public void activateJobs(
      final ActivateJobsRequest request,
      final ServerStreamObserver responseObserver) {
    activateJobsHandler.activateJobs(request, responseObserver);
  }

  public void cancelWorkflowInstance(
      final CancelWorkflowInstanceRequest request,
      final ServerStreamObserver responseObserver) {
    sendRequest(
        request,
        RequestMapper::toCancelWorkflowInstanceRequest,
        ResponseMapper::toCancelWorkflowInstanceResponse,
        responseObserver);
  }

  public void completeJob(
      final CompleteJobRequest request,
      final ServerStreamObserver responseObserver) {
    sendRequest(
        request,
        RequestMapper::toCompleteJobRequest,
        ResponseMapper::toCompleteJobResponse,
        responseObserver);
  }

  public void createWorkflowInstance(
      final CreateWorkflowInstanceRequest request,
      final ServerStreamObserver responseObserver) {
    sendRequestWithRetryPartitions(
        request,
        RequestMapper::toCreateWorkflowInstanceRequest,
        ResponseMapper::toCreateWorkflowInstanceResponse,
        responseObserver);
  }

  public void createWorkflowInstanceWithResult(
      final CreateWorkflowInstanceWithResultRequest request,
      final ServerStreamObserver responseObserver) {
    if (request.getRequestTimeout() > 0) {
      sendRequestWithRetryPartitions(
          request,
          RequestMapper::toCreateWorkflowInstanceWithResultRequest,
          ResponseMapper::toCreateWorkflowInstanceWithResultResponse,
          responseObserver,
          Duration.ofMillis(request.getRequestTimeout()));
    } else {
      sendRequestWithRetryPartitions(
          request,
          RequestMapper::toCreateWorkflowInstanceWithResultRequest,
          ResponseMapper::toCreateWorkflowInstanceWithResultResponse,
          responseObserver);
    }
  }

  public void deployWorkflow(
      final DeployWorkflowRequest request,
      final ServerStreamObserver responseObserver) {

    sendRequest(
        request,
        RequestMapper::toDeployWorkflowRequest,
        ResponseMapper::toDeployWorkflowResponse,
        responseObserver);
  }

  public void failJob(
      final FailJobRequest request, final ServerStreamObserver responseObserver) {
    sendRequest(
        request,
        RequestMapper::toFailJobRequest,
        ResponseMapper::toFailJobResponse,
        responseObserver);
  }

  public void throwError(
      final ThrowErrorRequest request,
      final ServerStreamObserver responseObserver) {
    sendRequest(
        request,
        RequestMapper::toThrowErrorRequest,
        ResponseMapper::toThrowErrorResponse,
        responseObserver);
  }

  public void publishMessage(
      final PublishMessageRequest request,
      final ServerStreamObserver responseObserver) {

    sendRequest(
        request,
        RequestMapper::toPublishMessageRequest,
        ResponseMapper::toPublishMessageResponse,
        responseObserver);
  }

  public void resolveIncident(
      final ResolveIncidentRequest request,
      final ServerStreamObserver responseObserver) {
    sendRequest(
        request,
        RequestMapper::toResolveIncidentRequest,
        ResponseMapper::toResolveIncidentResponse,
        responseObserver);
  }

  public void setVariables(
      final SetVariablesRequest request,
      final ServerStreamObserver responseObserver) {
    sendRequest(
        request,
        RequestMapper::toSetVariablesRequest,
        ResponseMapper::toSetVariablesResponse,
        responseObserver);
  }

  public void topology(
      final TopologyRequest request,
      final ServerStreamObserver responseObserver) {
    final TopologyResponse.Builder topologyResponseBuilder = TopologyResponse.newBuilder();
    final BrokerClusterState topology = topologyManager.getTopology();

    if (topology == null) {
      final StatusRuntimeException error =
          Status.UNAVAILABLE.augmentDescription("No brokers available").asRuntimeException();
      responseObserver.onError(error);
      return;
    }

    topologyResponseBuilder
        .setClusterSize(topology.getClusterSize())
        .setPartitionsCount(topology.getPartitionsCount())
        .setReplicationFactor(topology.getReplicationFactor());

    final String gatewayVersion = VersionUtil.getVersion();
    if (gatewayVersion != null && !gatewayVersion.isBlank()) {
      topologyResponseBuilder.setGatewayVersion(gatewayVersion);
    }

    final ArrayList brokers = new ArrayList<>();

    topology
        .getBrokers()
        .forEach(
            brokerId -> {
              final Builder brokerInfo = BrokerInfo.newBuilder();
              addBrokerInfo(brokerInfo, brokerId, topology);
              addPartitionInfoToBrokerInfo(brokerInfo, brokerId, topology);

              brokers.add(brokerInfo.build());
            });

    topologyResponseBuilder.addAllBrokers(brokers);
    final TopologyResponse response = topologyResponseBuilder.build();
    responseObserver.onNext(response);
    responseObserver.onCompleted();
  }

  public void updateJobRetries(
      final UpdateJobRetriesRequest request,
      final ServerStreamObserver responseObserver) {
    sendRequest(
        request,
        RequestMapper::toUpdateJobRetriesRequest,
        ResponseMapper::toUpdateJobRetriesResponse,
        responseObserver);
  }

  private  void sendRequest(
      final GrpcRequestT grpcRequest,
      final Function> requestMapper,
      final BrokerResponseMapper responseMapper,
      final ServerStreamObserver streamObserver) {
    final BrokerRequest brokerRequest;

    try {
      brokerRequest = requestMapper.apply(grpcRequest);
    } catch (final Exception e) {
      streamObserver.onError(e);
      return;
    }

    brokerClient.sendRequestWithRetry(
        brokerRequest,
        (key, response) -> consumeResponse(responseMapper, streamObserver, key, response),
        streamObserver::onError);
  }

  private  void sendRequestWithRetryPartitions(
      final GrpcRequestT grpcRequest,
      final Function> requestMapper,
      final BrokerResponseMapper responseMapper,
      final ServerStreamObserver streamObserver) {
    final BrokerRequest brokerRequest;

    try {
      brokerRequest = requestMapper.apply(grpcRequest);
    } catch (final Exception e) {
      streamObserver.onError(e);
      return;
    }

    requestRetryHandler.sendRequest(
        brokerRequest,
        (key, response) -> consumeResponse(responseMapper, streamObserver, key, response),
        streamObserver::onError);
  }

  private  void sendRequestWithRetryPartitions(
      final GrpcRequestT grpcRequest,
      final Function> requestMapper,
      final BrokerResponseMapper responseMapper,
      final ServerStreamObserver streamObserver,
      final Duration timeout) {
    final BrokerRequest brokerRequest;

    try {
      brokerRequest = requestMapper.apply(grpcRequest);
    } catch (final Exception e) {
      streamObserver.onError(e);
      return;
    }

    requestRetryHandler.sendRequest(
        brokerRequest,
        (key, response) -> consumeResponse(responseMapper, streamObserver, key, response),
        streamObserver::onError,
        timeout);
  }

  private  void consumeResponse(
      final BrokerResponseMapper responseMapper,
      final ServerStreamObserver streamObserver,
      final long key,
      final BrokerResponseT response) {
    final GrpcResponseT grpcResponse = responseMapper.apply(key, response);
    streamObserver.onNext(grpcResponse);
    streamObserver.onCompleted();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy