[wip] initial commit
extracted useful snippets from other projects
This commit is contained in:
commit
b950c9ebdb
26 changed files with 1362 additions and 0 deletions
68
src/de/pzzz/vertx/process/ExecutableProcess.java
Executable file
68
src/de/pzzz/vertx/process/ExecutableProcess.java
Executable 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;
|
||||
}
|
||||
}
|
44
src/de/pzzz/vertx/process/ItemProcess.java
Executable file
44
src/de/pzzz/vertx/process/ItemProcess.java
Executable 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;
|
||||
}
|
||||
}
|
149
src/de/pzzz/vertx/process/ProcessController.java
Executable file
149
src/de/pzzz/vertx/process/ProcessController.java
Executable 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()));
|
||||
}
|
||||
}
|
62
src/de/pzzz/vertx/process/ProcessExecutionController.java
Executable file
62
src/de/pzzz/vertx/process/ProcessExecutionController.java
Executable 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);
|
||||
}
|
||||
}
|
31
src/de/pzzz/vertx/process/ProcessRequest.java
Executable file
31
src/de/pzzz/vertx/process/ProcessRequest.java
Executable 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;
|
||||
}
|
||||
}
|
5
src/de/pzzz/vertx/process/ProcessStatus.java
Executable file
5
src/de/pzzz/vertx/process/ProcessStatus.java
Executable file
|
@ -0,0 +1,5 @@
|
|||
package de.pzzz.vertx.process;
|
||||
|
||||
public enum ProcessStatus {
|
||||
READY, RUNNING, COMPLETED, ERRORS, FAILED;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue