/* * Imixs-Workflow * * Copyright (C) 2001-2020 Imixs Software Solutions GmbH, * http://www.imixs.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You can receive a copy of the GNU General Public * License at http://www.gnu.org/licenses/gpl.html * * Project: * https://www.imixs.org * https://github.com/imixs/imixs-workflow * * Contributors: * Imixs Software Solutions GmbH - Project Management * Ralph Soika - Software Developer */ package ai.dynamixs.rag.events; import static org.imixs.workflow.engine.AsyncEventSchedulerConfig.ASYNCEVENT_PROCESSOR_DEADLOCK; import static org.imixs.workflow.engine.AsyncEventSchedulerConfig.ASYNCEVENT_PROCESSOR_ENABLED; import static org.imixs.workflow.engine.AsyncEventSchedulerConfig.ASYNCEVENT_PROCESSOR_INITIALDELAY; import static org.imixs.workflow.engine.AsyncEventSchedulerConfig.ASYNCEVENT_PROCESSOR_INTERVAL; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.imixs.workflow.engine.AsyncEventService; import org.imixs.workflow.engine.EventLogService; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import jakarta.annotation.security.DeclareRoles; import jakarta.annotation.security.RunAs; import jakarta.ejb.Singleton; import jakarta.ejb.Startup; import jakarta.ejb.Timeout; import jakarta.ejb.Timer; import jakarta.ejb.TimerConfig; import jakarta.ejb.TimerService; import jakarta.inject.Inject; /** * The RAGEventScheduler starts a scheduler service to process RAG events in an * asynchronous way by calling the RAGEventService. *

* The AsyncEventScheduler runs on a non-persistent ejb timer with the same * interval settings as the AsyncEventProcessor *

* RAGEventScheduler 'ASYNCEVENT_PROCESSOR_INTERVAL' and an optional delay * defined by 'ASYNCEVENT_PROCESSOR_INITIALDELAY'. To enable the processor * 'ASYNCEVENT_PROCESSOR_ENABLED' must be set to true (default=false). * 'ASYNCEVENT_PROCESSOR_DEADLOCK' deadlock timeout *

* In a clustered environment this timer runs in each cluster member that * contains the EJB. So this means the non-persistent EJB Timer scales * horizontal within a clustered environment – e.g. a Kubernetes cluster. * * @see AsyncEventService * @version 1.1 * @author rsoika * */ @DeclareRoles({ "org.imixs.ACCESSLEVEL.MANAGERACCESS" }) @RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS") @Startup @Singleton public class RAGEventScheduler { // enabled @Inject @ConfigProperty(name = ASYNCEVENT_PROCESSOR_ENABLED, defaultValue = "false") boolean enabled; // timeout interval in ms @Inject @ConfigProperty(name = ASYNCEVENT_PROCESSOR_INTERVAL, defaultValue = "1000") long interval; // initial delay in ms @Inject @ConfigProperty(name = ASYNCEVENT_PROCESSOR_INITIALDELAY, defaultValue = "0") long initialDelay; // deadlock timeout interval in ms @Inject @ConfigProperty(name = ASYNCEVENT_PROCESSOR_DEADLOCK, defaultValue = "60000") long deadLockInterval; private static final Logger logger = Logger.getLogger(RAGEventScheduler.class.getName()); @Resource TimerService timerService; @Inject RAGEventService ragEventService; @Inject EventLogService eventLogService; @PostConstruct public void init() { if (enabled) { // Registering a non-persistent Timer Service. final TimerConfig timerConfig = new TimerConfig(); timerConfig.setInfo("Imixs-Workflow AsyncEventScheduler"); timerConfig.setPersistent(false); timerService.createIntervalTimer(initialDelay, interval, timerConfig); logger.log(Level.INFO, "├── ✅ Started RAGEventScheduler - initalDelay={0} inverval={1}", new Object[] { initialDelay, interval }); } } /** * The method delegates the event processing to the stateless ejb * AsyncEventProcessor. *

* Before processing the eventLog the method releases possible dead locks first. * Both methods are running in separate transactions * */ @Timeout public void run(Timer timer) { eventLogService.releaseDeadLocks(deadLockInterval, RAGEventService.EVENTLOG_TOPIC_RAG_EVENT_INDEX, RAGEventService.EVENTLOG_TOPIC_RAG_EVENT_UPDATE, RAGEventService.EVENTLOG_TOPIC_RAG_EVENT_DELETE); ragEventService.processEventLog(); } }