Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions sdks/java/src/main/java/org/byteveda/taskito/DefaultTaskito.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import org.byteveda.taskito.core.CoreFacade;
import org.byteveda.taskito.errors.SerializationException;
import org.byteveda.taskito.errors.WorkflowException;
import org.byteveda.taskito.locks.Lock;
import org.byteveda.taskito.locks.LockInfo;
import org.byteveda.taskito.middleware.EnqueueContext;
Expand Down Expand Up @@ -377,7 +379,7 @@ public WorkflowRun submitWorkflow(Workflow workflow, Map<String, Object> supplie
// A payloadless structural step (stepAfter) must get its payload at
// submit; fail fast rather than enqueue a null-payload job.
if (payload == null && !suppliedPayloads.containsKey(step.name)) {
throw new TaskitoException("workflow step '" + step.name
throw new WorkflowException("workflow step '" + step.name
+ "' has no payload; supply one via submitWorkflow(wf, payloads)");
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
payloadNames.add(step.name);
Expand Down Expand Up @@ -491,13 +493,13 @@ private String encodeChild(Workflow child) {
// A child run has no submit-time payload map and no callable registry, so
// any step that depends on either would lose state — reject it at build time.
if ("callable".equals(step.condition)) {
throw new TaskitoException("child workflow step '" + step.name
throw new WorkflowException("child workflow step '" + step.name
+ "' uses condition(Condition); a sub-workflow cannot carry callable predicates");
}
boolean controlNode =
step.fanOut != null || step.fanIn != null || step.gate != null || step.subWorkflow != null;
if (!controlNode && step.payload == null) {
throw new TaskitoException("child workflow step '" + step.name
throw new WorkflowException("child workflow step '" + step.name
+ "' has no payload; a sub-workflow cannot supply child step payloads at submit");
}
specs.add(stepSpec(step));
Expand Down Expand Up @@ -547,15 +549,15 @@ private static String encode(Object value) {
try {
return VIEWS.writeValueAsString(value);
} catch (Exception e) {
throw new TaskitoException("failed to encode request", e);
throw new SerializationException("failed to encode request", e);
}
}

private static <R> R decode(String json, Class<R> type) {
try {
return VIEWS.readValue(json, type);
} catch (Exception e) {
throw new TaskitoException("failed to decode native response", e);
throw new SerializationException("failed to decode native response", e);
}
}

Expand All @@ -564,7 +566,7 @@ private static <R> List<R> decodeList(String json, Class<R> element) {
try {
return VIEWS.readValue(json, type);
} catch (Exception e) {
throw new TaskitoException("failed to decode native response", e);
throw new SerializationException("failed to decode native response", e);
}
}

Expand All @@ -573,7 +575,7 @@ private static <V> Map<String, V> decodeMap(String json, Class<V> value) {
try {
return VIEWS.readValue(json, type);
} catch (Exception e) {
throw new TaskitoException("failed to decode native response", e);
throw new SerializationException("failed to decode native response", e);
}
}
}
7 changes: 4 additions & 3 deletions sdks/java/src/main/java/org/byteveda/taskito/Taskito.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import org.byteveda.taskito.errors.ConfigurationException;
import org.byteveda.taskito.internal.JniQueueBackend;
import org.byteveda.taskito.locks.Lock;
import org.byteveda.taskito.locks.LockInfo;
Expand Down Expand Up @@ -288,7 +289,7 @@ public Taskito open() {
String dsn = (String) options.computeIfAbsent("dsn", key -> DEFAULT_SQLITE_DB);
ensureSqliteParentDir(dsn);
} else if (!options.containsKey("dsn")) {
throw new TaskitoException("url (dsn) is required");
throw new ConfigurationException("url (dsn) is required");
}
return new DefaultTaskito(JniQueueBackend.open(encodeOptions()), serializer);
}
Expand All @@ -305,15 +306,15 @@ private static void ensureSqliteParentDir(String dsn) {
try {
Files.createDirectories(parent);
} catch (IOException e) {
throw new TaskitoException("failed to create sqlite directory " + parent, e);
throw new ConfigurationException("failed to create sqlite directory " + parent, e);
}
}

private String encodeOptions() {
try {
return JSON.writeValueAsString(options);
} catch (Exception e) {
throw new TaskitoException("failed to encode open options", e);
throw new ConfigurationException("failed to encode open options", e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.byteveda.taskito.Taskito;
import org.byteveda.taskito.TaskitoException;
import org.byteveda.taskito.errors.SerializationException;
import org.byteveda.taskito.model.Job;
import org.byteveda.taskito.model.JobFilter;
import org.byteveda.taskito.model.JobStatus;
Expand Down Expand Up @@ -317,7 +317,7 @@ private static void respond(HttpExchange exchange, int status, Object body) thro
try {
out = JSON.writeValueAsBytes(body);
} catch (Exception e) {
throw new TaskitoException("failed to encode response", e);
throw new SerializationException("failed to encode response", e);
}
exchange.getResponseHeaders().set("Content-Type", "application/json");
exchange.sendResponseHeaders(status, out.length);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.byteveda.taskito.errors;

import org.byteveda.taskito.TaskitoException;

/**
* The SDK was misconfigured — e.g. a required connection URL is missing, or a
* storage directory could not be created.
*/
public class ConfigurationException extends TaskitoException {
public ConfigurationException(String message) {
super(message);
}

public ConfigurationException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.byteveda.taskito.errors;

/**
* A cryptographic operation in a signing or encrypting serializer failed —
* encryption/decryption, HMAC computation, a signature mismatch, or a payload
* too short to carry its tag/IV. A {@link SerializationException} because it
* occurs while (de)serializing a secured payload.
*/
public class CryptoException extends SerializationException {
public CryptoException(String message) {
super(message);
}

public CryptoException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.byteveda.taskito.errors;

import org.byteveda.taskito.TaskitoException;

/**
* A distributed lock operation failed or was interrupted while waiting to
* acquire the lock.
*/
public class LockException extends TaskitoException {
public LockException(String message) {
super(message);
}

public LockException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.byteveda.taskito.errors;

import org.byteveda.taskito.TaskitoException;

/**
* A payload, option blob, or native response could not be serialized or
* deserialized — e.g. an unregistered type, malformed JSON, or a result whose
* shape does not match the expected class.
*/
public class SerializationException extends TaskitoException {
public SerializationException(String message) {
super(message);
}

public SerializationException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.byteveda.taskito.errors;

import org.byteveda.taskito.TaskitoException;

/**
* A webhook could not be stored, loaded, signed, or its payload encoded.
*/
public class WebhookException extends TaskitoException {
public WebhookException(String message) {
super(message);
}

public WebhookException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.byteveda.taskito.errors;

import org.byteveda.taskito.TaskitoException;

/**
* A workflow could not be driven to completion — e.g. a run was not found, a
* deferred node has no registered payload, a callable condition was not
* registered on the worker, or awaiting a run was interrupted.
*/
public class WorkflowException extends TaskitoException {
public WorkflowException(String message) {
super(message);
}

public WorkflowException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Specific unchecked exceptions for Taskito failure scenarios.
*
* <p>All extend {@link org.byteveda.taskito.TaskitoException}, so a caller can
* catch the base type to handle any SDK error, or a specific subtype
* ({@link org.byteveda.taskito.errors.SerializationException},
* {@link org.byteveda.taskito.errors.WorkflowException}, etc.) to react to one
* category. Native (JNI) errors surface as the base {@code TaskitoException}.
*/
package org.byteveda.taskito.errors;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.byteveda.taskito.events;

import org.byteveda.taskito.TaskitoException;
import org.byteveda.taskito.errors.SerializationException;

/** Terminal outcome of a job, delivered to worker event listeners. */
public enum EventName {
Expand All @@ -21,7 +21,7 @@ public static EventName fromKind(String kind) {
case "cancelled":
return CANCELLED;
default:
throw new TaskitoException("unknown outcome kind: " + kind);
throw new SerializationException("unknown outcome kind: " + kind);
}
}
}
4 changes: 2 additions & 2 deletions sdks/java/src/main/java/org/byteveda/taskito/locks/Lock.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.time.Duration;
import java.util.UUID;
import org.byteveda.taskito.TaskitoException;
import org.byteveda.taskito.errors.LockException;
import org.byteveda.taskito.spi.QueueBackend;

/**
Expand Down Expand Up @@ -40,7 +40,7 @@ public boolean tryAcquire(Duration timeout) {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new TaskitoException("interrupted while acquiring lock '" + name + "'", e);
throw new LockException("interrupted while acquiring lock '" + name + "'", e);
}
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import java.util.Locale;
import org.byteveda.taskito.TaskitoException;
import org.byteveda.taskito.errors.SerializationException;

/** Lifecycle state of a job. Wire form is the lowercase name, shared across SDKs. */
public enum JobStatus {
Expand All @@ -22,12 +22,12 @@ public String wire() {
@JsonCreator
public static JobStatus fromWire(String wire) {
if (wire == null) {
throw new TaskitoException("job status is null");
throw new SerializationException("job status is null");
}
try {
return valueOf(wire.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
throw new TaskitoException("unknown job status: " + wire, e);
throw new SerializationException("unknown job status: " + wire, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.byteveda.taskito.TaskitoException;
import org.byteveda.taskito.errors.CryptoException;

/**
* Wraps a delegate serializer with AES-GCM encryption. Each payload is prefixed
Expand Down Expand Up @@ -40,7 +40,7 @@ public byte[] serialize(Object value) {
System.arraycopy(ciphertext, 0, out, IV_LENGTH, ciphertext.length);
return out;
} catch (Exception e) {
throw new TaskitoException("encryption failed", e);
throw new CryptoException("encryption failed", e);
}
}

Expand All @@ -57,7 +57,7 @@ public Object deserialize(byte[] bytes, Type type) {
/** Strip the IV, decrypt + authenticate (GCM), and return the plaintext. */
private byte[] decrypt(byte[] bytes) {
if (bytes.length < IV_LENGTH) {
throw new TaskitoException("encrypted payload is too short");
throw new CryptoException("encrypted payload is too short");
}
try {
byte[] iv = Arrays.copyOfRange(bytes, 0, IV_LENGTH);
Expand All @@ -66,7 +66,7 @@ private byte[] decrypt(byte[] bytes) {
cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(TAG_BITS, iv));
return cipher.doFinal(ciphertext);
} catch (Exception e) {
throw new TaskitoException("decryption failed", e);
throw new CryptoException("decryption failed", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Type;
import org.byteveda.taskito.TaskitoException;
import org.byteveda.taskito.errors.SerializationException;

/** Default {@link Serializer}: JSON via Jackson. */
public final class JsonSerializer implements Serializer {
Expand All @@ -21,7 +21,7 @@ public byte[] serialize(Object value) {
try {
return mapper.writeValueAsBytes(value);
} catch (Exception e) {
throw new TaskitoException("failed to serialize payload", e);
throw new SerializationException("failed to serialize payload", e);
}
}

Expand All @@ -30,7 +30,7 @@ public <T> T deserialize(byte[] bytes, Class<T> type) {
try {
return mapper.readValue(bytes, type);
} catch (Exception e) {
throw new TaskitoException("failed to deserialize payload", e);
throw new SerializationException("failed to deserialize payload", e);
}
}

Expand All @@ -39,7 +39,7 @@ public Object deserialize(byte[] bytes, Type type) {
try {
return mapper.readValue(bytes, mapper.getTypeFactory().constructType(type));
} catch (Exception e) {
throw new TaskitoException("failed to deserialize payload", e);
throw new SerializationException("failed to deserialize payload", e);
}
}
}
Loading