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

com.instaclustr.cassandra.sidecar.coordination.OperationCallable Maven / Gradle / Ivy

There is a newer version: 2.0.0-alpha8
Show newest version
package com.instaclustr.cassandra.sidecar.coordination;

import static com.instaclustr.operations.Operation.State.FAILED;
import static java.lang.String.format;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.await;

import java.io.Closeable;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;

import com.instaclustr.cassandra.sidecar.rest.SidecarClient;
import com.instaclustr.cassandra.sidecar.rest.SidecarClient.OperationResult;
import com.instaclustr.operations.GlobalOperationProgressTracker;
import com.instaclustr.operations.Operation;
import com.instaclustr.operations.Operation.State;
import com.instaclustr.operations.OperationCoordinator.OperationCoordinatorException;
import com.instaclustr.operations.OperationRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class OperationCallable, T extends OperationRequest> implements Supplier>, Closeable {

    private static final Logger logger = LoggerFactory.getLogger(OperationCallable.class);

    protected Operation operation;
    protected final int timeout;
    protected final SidecarClient sidecarClient;
    private final GlobalOperationProgressTracker progressTracker;
    private final String phase;

    public OperationCallable(final Operation operation,
                             final int timeout,
                             final SidecarClient sidecarClient,
                             final GlobalOperationProgressTracker progressTracker,
                             final String phase) {
        this.operation = operation;
        this.sidecarClient = sidecarClient;
        this.progressTracker = progressTracker;
        this.phase = phase;
        this.timeout = timeout;
    }

    public abstract OperationResult sendOperation();

    @Override
    public Operation get() {
        logger.info(format("Submitting operation %s with request %s ",
                           operation.getClass().getCanonicalName(),
                           operation.request.toString()));

        final OperationResult operationResult = sendOperation();

        logger.info(format("Sent %s operation in phase %s to node %s", operation.type, phase, sidecarClient.getHost()));

        final AtomicReference floatAtomicReference = new AtomicReference<>((float) 0);

        await().timeout(timeout, HOURS).pollInterval(5, SECONDS).until(() -> {

            try {
                if (operationResult.operation != null) {
                    operation = sidecarClient.getOperation(operationResult.operation.id, operation.request);
                    final State returnedState = operation.state;

                    float delta = operation.progress - floatAtomicReference.get();
                    floatAtomicReference.set(floatAtomicReference.get() + delta);

                    progressTracker.update(delta);

                    if (FAILED == returnedState) {
                        throw new OperationCoordinatorException(format("Operation %s of type %s in phase %s against host %s has failed.",
                                                                       operation.id,
                                                                       operation.request.type,
                                                                       phase,
                                                                       sidecarClient.getHost()));
                    }

                    return State.TERMINAL_STATES.contains(returnedState);
                }

                throw new OperationCoordinatorException(format("Error while fetching state of operation %s of type %s in phase %s against host %s, returned code: %s",
                                                               operation.id,
                                                               operation.request.type,
                                                               phase,
                                                               sidecarClient.getHost(),
                                                               operationResult.response.getStatus()));
            } catch (final Exception ex) {
                progressTracker.complete();
                operation.failureCause = null;
                operation.state = FAILED;
                operation.completionTime = Instant.now();
                operation.failureCause = ex;
                throw ex;
            }
        });

        final String logMessage = format("operation %s against node %s with hostId %s has finished with state %s.",
                                         operation.id,
                                         sidecarClient.getHost(),
                                         sidecarClient.getHostId(),
                                         operation.state);

        if (operation.state == FAILED) {
            logger.error(logMessage);
        } else {
            logger.info(logMessage);
        }

        return operation;
    }

    @Override
    public void close() {
        try {
            sidecarClient.close();
        } catch (final Exception ex) {
            logger.error(format("Unable to close callable for %s", sidecarClient.getHost()));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy