[wip] initial commit

extracted useful snippets from other projects
This commit is contained in:
Peter Eiser 2021-12-17 07:31:44 +01:00
commit b950c9ebdb
26 changed files with 1362 additions and 0 deletions

View file

@ -0,0 +1,68 @@
package de.pzzz.vertx.process;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import de.pzzz.vertx.SerializableWithId;
public abstract class ExecutableProcess<T extends Serializable, U extends ItemProcess<T>> extends SerializableWithId {
private static final long serialVersionUID = 4475632132455503715L;
private String name;
private ProcessStatus status;
private int parallelRequests = 1;
private List<U> processingItems;
public ExecutableProcess() {
super();
}
public ExecutableProcess(final ProcessRequest<T> request) {
super();
this.name = request.getName();
this.status = ProcessStatus.READY;
this.parallelRequests = request.getParallelRequests();
this.processingItems = new ArrayList<>();
Set<T> itemRequests = new HashSet<>(request.getProcessingItems());
for (T itemRequest: itemRequests) {
processingItems.add(getItemProcess(itemRequest));
}
}
protected abstract U getItemProcess(final T itemRequest);
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public ProcessStatus getStatus() {
return status;
}
public void setStatus(final ProcessStatus status) {
this.status = status;
}
public int getParallelRequests() {
return parallelRequests;
}
public void setParallelRequests(final int parallelRequests) {
this.parallelRequests = parallelRequests;
}
public List<U> getProcessingItems() {
return processingItems;
}
public void setProcessingItems(final List<U> processingItems) {
this.processingItems = processingItems;
}
}

View file

@ -0,0 +1,44 @@
package de.pzzz.vertx.process;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class ItemProcess<T extends Serializable> implements Serializable {
private static final long serialVersionUID = -152613060384269555L;
private T item;
private List<String> messages = new ArrayList<>();
public ItemProcess() {}
public ItemProcess(final T item) {
this();
this.item = item;
}
public void setErrorState() {}
public void addMessage(final String message) {
if (null == messages) {
messages = new ArrayList<>();
}
messages.add(message);
}
public T getItem() {
return item;
}
public void setItem(final T item) {
this.item = item;
}
public List<String> getMessages() {
return messages;
}
public void setMessages(final List<String> messages) {
this.messages = messages;
}
}

View file

@ -0,0 +1,149 @@
package de.pzzz.vertx.process;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import de.pzzz.vertx.worker.QueueProcessingStatus;
import de.pzzz.vertx.PersistentRestDataAccess;
import de.pzzz.vertx.Startup;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.json.Json;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
public abstract class ProcessController<T extends ExecutableProcess<V,U>, U extends ItemProcess<V>,V extends Serializable, W> extends PersistentRestDataAccess<T> {
private Map<String, ProcessExecutionController<T,U,V,W>> executors = new HashMap<>();
private final Vertx vertx;
private final Startup startup;
public ProcessController(final Class<T> classReference, final Vertx vertx, final Startup startup, final String baseDir) {
super(classReference, vertx, baseDir);
this.vertx = vertx;
this.startup = startup;
}
@Override
public void delete(final String id) {
//TODO work with Future and improve error handling
if (executors.containsKey(id)) {
ProcessExecutionController<T,U,V,W> executor = executors.get(id);
executor.stopProcessing();
executor.close(null);
}
super.delete(id);
}
@Override
protected void update(final String id, final RoutingContext context) {
if (!get(id).getStatus().equals(ProcessStatus.READY)) {
context.fail(405);
return;
}
//TODO work with Future and improve error handling
if (executors.containsKey(id)) {
ProcessExecutionController<T,U,V,W> executor = executors.get(id);
executor.stopProcessing();
executor.close(null);
}
T newData = getDataFromRequest(context);
newData.setId(id);
update(newData);
}
@Override
public void registerRoutes(final Router router, final String baseUrl) {
super.registerRoutes(router, baseUrl);
router.post(baseUrl + "/:id/start").handler(this::startProcessing);
router.get(baseUrl + "/:id/status").handler(this::processStatus);
router.post(baseUrl + "/:id/stop").handler(this::stopProcessing);
router.post(baseUrl + "/:id/clear").handler(this::clearProcessingQueue);
}
abstract protected ProcessExecutionController<T,U,V,W> createNewProcessExecutionController(final T process, final Vertx vertx, final Startup startup, final String id);
private void startProcessing(final RoutingContext context) {
if (context.response().ended()) {
return;
}
final String id = context.pathParam("id");
if (!contains(id)) {
context.fail(404);
return;
}
startOrContinueProcessing(id)
.onSuccess(status -> context.response().end(Json.encodePrettily(status)))
.onFailure(error -> context.fail(500));
}
private Future<QueueProcessingStatus<U>> startOrContinueProcessing(final String id) {
Promise<QueueProcessingStatus<U>> promise = Promise.promise();
if (!executors.containsKey(id)) {
T process = get(id);
process.setStatus(ProcessStatus.RUNNING);
ProcessExecutionController<T,U,V,W> executor = createNewProcessExecutionController(process, vertx, startup, id);
executors.put(id, executor);
executor.deployWorkers()
.onSuccess(res -> promise.complete(executor.startProcessing()))
.onFailure(error -> promise.fail(error));
} else {
ProcessExecutionController<T,U,V,W> executor = executors.get(id);
promise.complete(executor.continueProcessing());
}
return promise.future();
}
private void processStatus(final RoutingContext context) {
if (context.response().ended()) {
return;
}
final String id = context.pathParam("id");
if (!contains(id)) {
context.fail(404);
return;
}
if (!executors.containsKey(id)) {
context.fail(400);
return;
}
ProcessExecutionController<T,U,V,W> executor = executors.get(id);
context.response().end(Json.encodePrettily(executor.processingStatus()));
}
private void stopProcessing(final RoutingContext context) {
if (context.response().ended()) {
return;
}
final String id = context.pathParam("id");
if (!contains(id)) {
context.fail(404);
return;
}
if (!executors.containsKey(id)) {
context.fail(400);
return;
}
ProcessExecutionController<T,U,V,W> executor = executors.get(id);
context.response().end(Json.encodePrettily(executor.stopProcessing()));
}
private void clearProcessingQueue(final RoutingContext context) {
if (context.response().ended()) {
return;
}
final String id = context.pathParam("id");
if (!contains(id)) {
context.fail(404);
return;
}
if (!executors.containsKey(id)) {
context.fail(400);
return;
}
ProcessExecutionController<T,U,V,W> executor = executors.get(id);
context.response().end(Json.encodePrettily(executor.clearQueue()));
}
}

View file

@ -0,0 +1,62 @@
package de.pzzz.vertx.process;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import de.pzzz.vertx.Startup;
import de.pzzz.vertx.worker.DeployableWorker;
import de.pzzz.vertx.worker.QueuedWorker;
import io.vertx.core.Closeable;
import io.vertx.core.CompositeFuture;
import io.vertx.core.Future;
import io.vertx.core.Promise;
public abstract class ProcessExecutionController<T extends ExecutableProcess<V,U>, U extends ItemProcess<V>, V extends Serializable, W>
extends QueuedWorker<U,W> implements Closeable {
private static final Logger LOG = Logger.getLogger(ProcessExecutionController.class.getName());
private final T process;
private final Startup startup;
public ProcessExecutionController(final T process, final Startup startup) {
super(process.getParallelRequests());
this.process = process;
this.startup = startup;
}
public Future<Void> deployWorkers() {
Promise<Void> promise = Promise.promise();
CompositeFuture.all(getWorker().stream().map(controller -> (Future) controller.deployWorkers(startup)).toList())
.onSuccess(res -> promise.complete())
.onFailure(error -> {
LOG.log(Level.SEVERE, error.getMessage(), error);
promise.fail(error);
});
return promise.future();
}
@Override
public void close(final Promise<Void> completion) {
CompositeFuture.all(getWorker().stream().map(worker -> (Future) worker.undeployWorkers()).toList())
.onSuccess(res -> completion.complete())
.onFailure(error -> {
LOG.log(Level.SEVERE, error.getMessage(), error);
completion.fail(error);
});
}
protected abstract List<DeployableWorker> getWorker();
protected T getProcess() {
return process;
}
protected void handleJobFailure(final U job, final Throwable error, final Promise<?> promise) {
LOG.log(Level.WARNING, "Failed job for " + job.getItem() + " with error " + error.getMessage(), error);
job.setErrorState();
job.addMessage(error.getMessage());
promise.fail(error);
}
}

View file

@ -0,0 +1,31 @@
package de.pzzz.vertx.process;
import java.io.Serializable;
import java.util.List;
public class ProcessRequest<T> implements Serializable {
private static final long serialVersionUID = 4946708367771253605L;
private String name;
private List<T> processingItems;
private int parallelRequests = 1;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public List<T> getProcessingItems() {
return processingItems;
}
public void setProcessingItems(final List<T> processingItems) {
this.processingItems = processingItems;
}
public int getParallelRequests() {
return parallelRequests;
}
public void setParallelRequests(final int parallelRequests) {
this.parallelRequests = parallelRequests;
}
}

View file

@ -0,0 +1,5 @@
package de.pzzz.vertx.process;
public enum ProcessStatus {
READY, RUNNING, COMPLETED, ERRORS, FAILED;
}