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

com.evento.application.consumer.ProjectorEvenConsumer Maven / Gradle / Ivy

Go to download

Evento Framework - Bundle. The library to build a RECQ System based on Evento Server

The newest version!
package com.evento.application.consumer;

import com.evento.application.performance.TracingAgent;
import com.evento.application.reference.ProjectorReference;
import lombok.Getter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.evento.application.proxy.GatewayTelemetryProxy;
import com.evento.common.messaging.consumer.ConsumerStateStore;
import com.evento.common.modeling.messaging.message.application.Message;
import com.evento.common.utils.ProjectorStatus;
import com.evento.common.utils.Sleep;

import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Supplier;

/**
 * Represents a consumer for projector events, responsible for processing and handling events
 * in a projector context.
 */
public class ProjectorEvenConsumer extends EventConsumer {

    private static final Logger logger = LogManager.getLogger(ProjectorEvenConsumer.class);

    // Fields for configuration and dependencies
    @Getter
    private final String bundleId;
    @Getter
    private final String projectorName;
    @Getter
    private final int projectorVersion;
    @Getter
    private final String context;
    private final Supplier isShuttingDown;
    private final HashMap> projectorMessageHandlers;
    private final TracingAgent tracingAgent;
    private final BiFunction, GatewayTelemetryProxy> gatewayTelemetryProxy;
    @Getter
    private final int sssFetchSize;
    @Getter
    private final int sssFetchDelay;
    private final AtomicInteger alignmentCounter;
    private final Runnable onAllHeadReached;

    /**
     * Constructs a new ProjectorEvenConsumer with the specified parameters.
     *
     * @param bundleId                 The bundle identifier.
     * @param projectorName            The name of the projector.
     * @param projectorVersion         The version of the projector.
     * @param context                  The context in which the projector operates.
     * @param isShuttingDown           A supplier indicating whether the consumer is shutting down.
     * @param consumerStateStore       The state store for tracking consumer state.
     * @param projectorMessageHandlers The map of event names to projector handlers.
     * @param tracingAgent             The tracing agent for tracking events.
     * @param gatewayTelemetryProxy    The function for creating a telemetry proxy for a gateway.
     * @param sssFetchSize             The fetch size for consuming events from the state store.
     * @param sssFetchDelay            The delay for fetching events from the state store.
     * @param alignmentCounter         The atomic counter for tracking alignment.
     * @param onAllHeadReached            The runnable to execute when the head is reached.
     */
    public ProjectorEvenConsumer(String bundleId,
                                 String projectorName, int projectorVersion,
                                 String context, Supplier isShuttingDown,
                                 ConsumerStateStore consumerStateStore,
                                 HashMap> projectorMessageHandlers,
                                 TracingAgent tracingAgent, BiFunction,
            GatewayTelemetryProxy> gatewayTelemetryProxy, int sssFetchSize,
                                 int sssFetchDelay, AtomicInteger alignmentCounter,
                                 Runnable onAllHeadReached) {
        super(bundleId + "_" + projectorName + "_" + projectorVersion + "_" + context, consumerStateStore);
        // Initialization of fields
        this.bundleId = bundleId;
        this.projectorName = projectorName;
        this.projectorVersion = projectorVersion;
        this.context = context;
        this.isShuttingDown = isShuttingDown;
        this.projectorMessageHandlers = projectorMessageHandlers;
        this.tracingAgent = tracingAgent;
        this.gatewayTelemetryProxy = gatewayTelemetryProxy;
        this.sssFetchSize = sssFetchSize;
        this.sssFetchDelay = sssFetchDelay;
        this.alignmentCounter = alignmentCounter;
        this.onAllHeadReached = onAllHeadReached;
    }

    /**
     * Runs the projector event consumer, continuously processing and handling events
     * until the shutdown condition is met.
     */
    @Override
    public void run() {

        // Initialize projector status
        var ps = new ProjectorStatus();
        ps.setHeadReached(false);


        // Main loop for event processing
        while (!isShuttingDown.get()) {
            var hasError = false;
            var consumedEventCount = 0;

            try {
                // Consume events from the state store and process them
                consumedEventCount = consumerStateStore.consumeEventsForProjector(
                        consumerId,
                        projectorName,
                        context,
                        publishedEvent -> {
                            // Retrieve handlers for the event name
                            var handlers = projectorMessageHandlers
                                    .get(publishedEvent.getEventName());
                            if (handlers == null) return;

                            // Retrieve the handler for the current projector
                            var handler = handlers.getOrDefault(projectorName, null);
                            if (handler == null) return;

                            // Create telemetry proxy for the gateway
                            var proxy = gatewayTelemetryProxy.apply(handler.getComponentName(),
                                    publishedEvent.getEventMessage());

                            // Track the event using the tracing agent
                            tracingAgent.track(publishedEvent.getEventMessage(), handler.getComponentName(),
                                    null,
                                    () -> {
                                        // Invoke the handler and send telemetry metrics
                                        handler.invoke(
                                                publishedEvent,
                                                proxy,
                                                proxy,
                                                ps
                                        );
                                        proxy.sendInvocationsMetric();
                                        return null;
                                    });

                        }, sssFetchSize);
            } catch (Throwable e) {
                logger.error("Error on projector consumer: " + consumerId, e);
                hasError = true;
            }

            // Sleep based on fetch size and error conditions
            if (sssFetchSize - consumedEventCount > 10) {
                Sleep.apply(hasError ? sssFetchDelay : sssFetchSize - consumedEventCount);
            }

            // Check for head reached condition and execute onHeadReached if necessary
            if (!hasError && !ps.isHeadReached() && consumedEventCount >= 0 && consumedEventCount < sssFetchSize) {
                ps.setHeadReached(true);
                logger.info("Event consumer head Reached for Projector: %s - Version: %d - Context: %s"
                        .formatted(projectorName, projectorVersion, context));
                var aligned = alignmentCounter.decrementAndGet();
                if (aligned == 0) {
                    onAllHeadReached.run();
                }
            }
        }
    }

    public void consumeDeadEventQueue() throws Exception {

        // Initialize projector status
        var ps = new ProjectorStatus();
        ps.setHeadReached(true);

        consumerStateStore.consumeDeadEventsForProjector(
                consumerId,
                projectorName,
                publishedEvent -> {
                    // Retrieve handlers for the event name
                    var handlers = projectorMessageHandlers
                            .get(publishedEvent.getEventName());
                    if (handlers == null) return;

                    // Retrieve the handler for the current projector
                    var handler = handlers.getOrDefault(projectorName, null);
                    if (handler == null) return;

                    // Create telemetry proxy for the gateway
                    var proxy = gatewayTelemetryProxy.apply(handler.getComponentName(),
                            publishedEvent.getEventMessage());

                    // Track the event using the tracing agent
                    tracingAgent.track(publishedEvent.getEventMessage(), handler.getComponentName(),
                            null,
                            () -> {
                                // Invoke the handler and send telemetry metrics
                                handler.invoke(
                                        publishedEvent,
                                        proxy,
                                        proxy,
                                        ps
                                );
                                proxy.sendInvocationsMetric();
                                return null;
                            });

                }
        );
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy