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

io.camunda.zeebe.broker.system.partitions.ZeebePartitionHealth Maven / Gradle / Ivy

There is a newer version: 8.7.0-alpha1
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.zeebe.broker.system.partitions;

import io.camunda.zeebe.util.health.FailureListener;
import io.camunda.zeebe.util.health.HealthMonitorable;
import io.camunda.zeebe.util.health.HealthReport;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * Reflects the health of ZeebePartition. The health is updated by ZeebePartition when role
 * transitions either succeeded or failed.
 */
class ZeebePartitionHealth implements HealthMonitorable {

  private final String name;
  private final Set failureListeners = new HashSet<>();
  private HealthReport healthReport;
  private final PartitionTransition partitionTransition;
  /*
  Multiple factors determine ZeebePartition's health :
  * - servicesInstalled: indicates if role transition was successful and all services are installed
  * - diskSpaceAvailable
  * - if the partition is not blocked in a transition step
  */
  private boolean servicesInstalled;
  // We assume disk space is available until otherwise notified
  private boolean diskSpaceAvailable = true;

  public ZeebePartitionHealth(
      final int partitionId, final PartitionTransition partitionTransition) {
    name = "ZeebePartition-" + partitionId;
    this.partitionTransition = partitionTransition;
  }

  private void updateHealthStatus() {
    final HealthReport previousStatus = healthReport;
    if (previousStatus != null && previousStatus.isDead()) {
      return;
    }

    final var partitionTransitionHealthIssue = partitionTransition.getHealthIssue();
    if (!diskSpaceAvailable) {
      healthReport = HealthReport.unhealthy(this).withMessage("Not enough disk space available");
    } else if (partitionTransitionHealthIssue != null) {
      healthReport = HealthReport.unhealthy(this).withIssue(partitionTransitionHealthIssue);
    } else if (!servicesInstalled) {
      healthReport = HealthReport.unhealthy(this).withMessage("Services not installed");
    } else {
      healthReport = HealthReport.healthy(this);
    }

    if (!Objects.equals(previousStatus, healthReport)) {
      switch (healthReport.getStatus()) {
        case HEALTHY -> failureListeners.forEach(FailureListener::onRecovered);
        case UNHEALTHY -> failureListeners.forEach((l) -> l.onFailure(healthReport));
        case DEAD -> failureListeners.forEach((l) -> l.onUnrecoverableFailure(healthReport));
        default -> {}
      }
    }
  }

  void setServicesInstalled(final boolean servicesInstalled) {
    this.servicesInstalled = servicesInstalled;
    updateHealthStatus();
  }

  void setDiskSpaceAvailable(final boolean diskSpaceAvailable) {
    this.diskSpaceAvailable = diskSpaceAvailable;
    updateHealthStatus();
  }

  void onUnrecoverableFailure(final Throwable error) {
    healthReport = HealthReport.dead(this).withIssue(error);
  }

  @Override
  public String getName() {
    return name;
  }

  @Override
  public HealthReport getHealthReport() {
    updateHealthStatus();
    return healthReport;
  }

  @Override
  public void addFailureListener(final FailureListener failureListener) {
    failureListeners.add(failureListener);
  }

  @Override
  public void removeFailureListener(final FailureListener failureListener) {
    failureListeners.remove(failureListener);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy