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

dev.sixpack.generator.FactoryController Maven / Gradle / Ivy

The newest version!
package dev.sixpack.generator;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import dev.sixpack.api.data.*;
import dev.sixpack.api.exception.IterateRequest;
import dev.sixpack.api.exception.NonRetryableException;
import io.temporal.workflow.Workflow;

import java.time.Duration;

import org.slf4j.Logger;

import java.lang.reflect.InvocationTargetException;
import java.time.Instant;

public class FactoryController {

    public static final Integer MAX_RETRIES = 5;
    public static final Duration INITIAL_INTERVAL = Duration.ofSeconds(5);
    public static final Integer BACKOFF_COEFFICIENT = 2;
    public static final Duration MAXIMUM_INTERVAL = Duration.ofMinutes(1);
    private final static ObjectMapper MAPPER = new ObjectMapper();

    static {
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        MAPPER.registerModule(new JavaTimeModule());
    }

    /**
     * This method must be called from Workflows only. It will handle retries since they don't work as expected
     *
     * @return
     */
    public static Result generateWithRetries(Request request, Logger LOGGER, FactoryRecord factoryRecord) {
        int attempt = 1;
        Duration interval = INITIAL_INTERVAL;
        while (true) {
            LOGGER.debug("Executing orchestrator, attempt: " + attempt);
            try {
                return generate(request, LOGGER, factoryRecord);
            } catch (Exception e) {
                if (attempt >= MAX_RETRIES) {
                    LOGGER.debug("Orchestrator {} with configuration {} failed", request.getItemName(), request.getInput());
                    return Result.failed(e.getMessage(), request.getContextMap());
                }
                LOGGER.error("Exception occurred in orchestrator {}, configuration {}. Retrying in {} s",
                        request.getItemName(),
                        request.getInput(),
                        interval.getSeconds(),
                        e);
                Workflow.sleep(interval);
                attempt++;
                // increase interval
                interval = interval.multipliedBy(BACKOFF_COEFFICIENT);
                if (interval.compareTo(MAXIMUM_INTERVAL) > 0) {
                    interval = MAXIMUM_INTERVAL;
                }
            }
        }
    }


    /**
     * Main generation method.
     * It will return a Result if generation is successful, or if NonRetriable or IterateRequest exceptions were thrown during
     * generator/orchestrator generate method execution
     * If other exception is thrown during Factory.generate() method, it will not be caught
     *
     * @param request Request coming from Sixpack backend through temporal
     * @return Result which may represent success, failure or iteration request
     */
    public static Result generate(Request request, Logger LOGGER, FactoryRecord factoryRecord) {
        String itemName = request.getItemName();
        Configuration input = request.getInput();
        Object generatorInput = MAPPER.convertValue(input, factoryRecord.getInput());
        int iteration = request.getIteration();
        JMap configuration = request.getContextMap() != null ? request.getContextMap() : new JMap();
        Context context = new Context(iteration, configuration);
        LOGGER.debug("Generating {} with configuration {} iteration {}",
                itemName,
                generatorInput,
                iteration);
        try {
            FactoryInterface factory = getFactory(factoryRecord, request.getId());
            Object factoryOutput = factory.generate(generatorInput, context);
            LOGGER.debug("Sending back final output {}", factoryOutput);
            Configuration output = MAPPER.convertValue(factoryOutput, Configuration.class);
            LOGGER.debug("Sending back with status OK");
            return new Result(ResultStatus.OK,
                    null,
                    null,
                    null,
                    output,
                    Instant.now());
        } catch (IterateRequest iterateRequest) {
            LOGGER.debug("Next iteration requested after {} with message {}",
                    iterateRequest.getTimeout(),
                    iterateRequest.getMessage());
            return new Result(ResultStatus.ITERATE,
                    iterateRequest.getMessage(),
                    context.getDetails(),
                    Instant.now().plus(iterateRequest.getTimeout()),
                    null,
                    Instant.now());
        } catch (NonRetryableException e) {
            return Result.failed(e.getMessage(), context.getDetails());
        }
    }

    private static FactoryInterface getFactory(FactoryRecord factoryRecord, String id) {
        Generator generator = factoryRecord.getGenerator();
        if (generator != null) {
            return generator;
        } else {
            try {
                Orchestrator orchestrator = factoryRecord.getOrchestrator().getDeclaredConstructor().newInstance();
                orchestrator.setEnvironment(factoryRecord.getEnvironment());
                orchestrator.setDatasetId(id);
                return orchestrator;
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                     NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy