Lifecycle.java

package com.github.jonasrutishauser.transactional.event.core.store;

import static jakarta.enterprise.event.Reception.IF_EXISTS;
import static jakarta.enterprise.event.TransactionPhase.AFTER_SUCCESS;
import static jakarta.interceptor.Interceptor.Priority.LIBRARY_AFTER;
import static jakarta.interceptor.Interceptor.Priority.LIBRARY_BEFORE;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.github.jonasrutishauser.transactional.event.core.cdi.Startup;
import com.github.jonasrutishauser.transactional.event.core.concurrent.EventExecutor;
import com.github.jonasrutishauser.transactional.event.core.concurrent.EventExecutor.Task;

import jakarta.annotation.PreDestroy;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.BeforeDestroyed;
import jakarta.enterprise.context.Initialized;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;

@ApplicationScoped
class Lifecycle implements Startup {

    private static final Logger LOGGER = LogManager.getLogger();

    private final Dispatcher dispatcher;
    private final EventExecutor executor;

    private Task scheduled;

    Lifecycle() {
        this(null, null);
    }

    @Inject
    Lifecycle(Dispatcher dispatcher, EventExecutor executor) {
        this.dispatcher = dispatcher;
        this.executor = executor;
    }

    void directDispatch(@Observes(during = AFTER_SUCCESS) @Priority(LIBRARY_BEFORE) EventsPublished events) {
        dispatcher.processDirect(events);
    }

    void startup(@Observes @Priority(LIBRARY_AFTER + 500) @Initialized(ApplicationScoped.class) Object event) {
        scheduled = executor.schedule(this::safeSchedule, dispatcher::dispatchInterval);
    }

    private void safeSchedule() {
        try {
            dispatcher.schedule();
        } catch (RuntimeException e) {
            LOGGER.warn("Failed to schedule event processing", e);
        }
    }

    void shutdown(@Observes(notifyObserver = IF_EXISTS) @Priority(LIBRARY_BEFORE) @BeforeDestroyed(ApplicationScoped.class) Object event) {
        stop();
    }

    @PreDestroy
    void stop() {
        if (scheduled != null) {
            scheduled.cancel();
            scheduled = null;
        }
    }

}