Added `BufferedEventProcessor` to manual send bunch of events and controlling their output status

This commit is contained in:
Mauro Mugnaini 2022-07-07 16:46:07 +02:00
parent a49e030d71
commit ec8476164c
4 changed files with 168 additions and 1 deletions

View File

@ -3,6 +3,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
# Changelog for "event-publisher-library"
## [v1.1.0-SNAPSHOT]
- Added `BufferedEventProcessor` to manual send bunch of events and controlling their output status
## [v1.0.2]
- Refactored/extracted event sender that uses OIDC token only and extended it for the UMA version.

View File

@ -21,7 +21,7 @@
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>maven-portal-bom</artifactId>
<version>3.6.3-SNAPSHOT</version>
<version>3.6.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@ -0,0 +1,152 @@
package org.gcube.event.publisher;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BufferedEventProcessor {
private static final Logger logger = LoggerFactory.getLogger(BufferedEventProcessor.class);
private static final int DEFAULT_BUFFER_SIZE = 10;
private static final int RESULT_POLLING_INTERVAL = 500;
private ArrayBlockingQueue<Event> eventsBuffer;
private Map<Runnable, Boolean> threadStatus;
private int count = 0;
private long min = 10000000000L;
private long max = 0;
private int errors = 0;
public BufferedEventProcessor(String conductorEndpoint, String clientId, String clientSecret,
String keycloakTokenEndpoint, Function<Event, String> logInfoGenerator)
throws EventProcessorException {
this(conductorEndpoint, clientId, clientSecret, keycloakTokenEndpoint, logInfoGenerator, DEFAULT_BUFFER_SIZE);
}
public BufferedEventProcessor(String conductorEndpoint, String clientId, String clientSecret,
String keycloakTokenEndpoint, Function<Event, String> logInfoGenerator, int bufferSize)
throws EventProcessorException {
eventsBuffer = new ArrayBlockingQueue<>(bufferSize, true);
threadStatus = Collections.synchronizedMap(new HashMap<>(bufferSize));
final AbstractEventPublisher publisher = new AbstractEventPublisher() {
@Override
protected EventSender createEventSender() {
try {
return new HTTPWithOIDCAuthEventSender(new URL(conductorEndpoint), clientId, clientSecret,
new URL(keycloakTokenEndpoint));
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
}
};
if (publisher.getEventSender() == null) {
throw new EventProcessorException("Cannot create procrssor correctly");
}
for (int i = 0; i < bufferSize; i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
String log = null;
Event toBeSent;
try {
toBeSent = eventsBuffer.take();
} catch (InterruptedException e) {
// interrupted when waiting, nothing to do...
continue;
}
long start = System.currentTimeMillis();
threadStatus.put(this, Boolean.TRUE);
logger.trace(" * Peeked event. Buffer size: {}", eventsBuffer.size());
log = logInfoGenerator.apply(toBeSent);
logger.debug(" > Sending event for: {}", log);
boolean sent = false;
String workflowId = null;
do {
try {
workflowId = publisher.publish(toBeSent, true);
sent = true;
} catch (Exception e) {
logger.warn("Publishing event for {}. It will be re-published", log, e);
}
} while (!sent);
EventStatus eventStatus;
do {
eventStatus = null;
try {
Thread.sleep(RESULT_POLLING_INTERVAL);
eventStatus = publisher.check(workflowId);
} catch (Exception e) {
logger.warn("Checking status for the event for {}", log, e);
}
if (eventStatus == null || eventStatus.getStatus() == null) {
continue;
}
} while (eventStatus.getStatus() != EventStatus.Status.COMPLETED
&& eventStatus.getStatus() != EventStatus.Status.FAILED);
long elapsed = System.currentTimeMillis() - start;
count = count + 1;
if (elapsed > max) {
max = elapsed;
}
if (elapsed < min) {
min = elapsed;
}
if (eventStatus.getStatus() == EventStatus.Status.FAILED) {
logger.warn(" - ({}) {} -> {} [{} ms]",
new Object[] { count, log, eventStatus.getStatus(), elapsed });
errors += 1;
} else {
logger.info(" - (" + count + ") " + log + " -> " + eventStatus.getStatus() + " ["
+ elapsed + " ms]");
}
threadStatus.put(this, Boolean.FALSE);
}
}
});
threadStatus.put(t, Boolean.FALSE);
t.start();
}
}
public void enqueueEvent(Event event) throws InterruptedException {
eventsBuffer.put(event);
}
public Boolean allQueuedFinishedCorrectly() {
return eventsBuffer.size() > 0 || threadStatus.values().stream().anyMatch(v -> v.equals(Boolean.TRUE));
}
public int getCount() {
return count;
}
public long getMin() {
return min;
}
public long getMax() {
return max;
}
public int getErrors() {
return errors;
}
}

View File

@ -0,0 +1,14 @@
package org.gcube.event.publisher;
public class EventProcessorException extends Exception {
private static final long serialVersionUID = 568668418901859597L;
public EventProcessorException(String message) {
super(message);
}
public EventProcessorException(String message, Throwable cause) {
super(message, cause);
}
}