Skip to content
Merged
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,10 @@ node_modules/
# bundled into wheels by CI. Not tracked so every rebuild doesn't churn git.
sdks/python/taskito/static/

# Java SDK: native libs + dashboard SPA staged into resources by CI at publish
# time (see publish-java.yml). Generated, not tracked.
sdks/java/src/main/resources/org/byteveda/taskito/native/
sdks/java/src/main/resources/org/byteveda/taskito/dashboard/

# Docs
site/
55 changes: 36 additions & 19 deletions sdks/java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,25 @@ A typed Java 11+ client over the Taskito Rust core, via a hand-written JNI shell
> distributed locks, periodic/cron, and static-DAG workflows are implemented and
> verified end-to-end.

## Migration

**0.18 — source-breaking (pre-1.0):** the client interface was renamed and the
name `Queue` now denotes a single named queue.

- The client you open is now `Taskito`, not `Queue`:
`Taskito client = Taskito.builder()…open();` (was `Queue queue = …`).
`Taskito.builder()` is unchanged.
- `Queue` is a per-queue handle from `Taskito.queue(name)`, exposing
`pause()` / `resume()` / `isPaused()`.
- `client.pauseQueue("emails")` → `client.queue("emails").pause()` (likewise
`resume`). `listPausedQueues()` stays on the client as the global view.

## Usage

### Enqueue

```java
import com.fasterxml.jackson.core.type.TypeReference;
import org.byteveda.taskito.Queue;
import org.byteveda.taskito.Taskito;
import org.byteveda.taskito.model.Job;
import org.byteveda.taskito.model.JobStatus;
Expand All @@ -29,11 +41,15 @@ Task<Map<String, Object>> sendEmail =
.queue("emails")
.priority(5);

try (Queue queue = Taskito.builder().sqlite("taskito.db").open()) {
String id = queue.enqueue(sendEmail, Map.of("to", "a@b.c"));
Job job = queue.getJob(id).orElseThrow(); // job.status == JobStatus.PENDING
QueueStats stats = queue.stats();
queue.cancel(id);
try (Taskito taskito = Taskito.builder().sqlite("taskito.db").open()) {
String id = taskito.enqueue(sendEmail, Map.of("to", "a@b.c"));
Job job = taskito.getJob(id).orElseThrow(); // job.status == JobStatus.PENDING
QueueStats stats = taskito.stats();
taskito.cancel(id);

// Pause/resume are scoped to one named queue:
taskito.queue("emails").pause();
taskito.queue("emails").resume();
}
```

Expand All @@ -48,8 +64,8 @@ import org.byteveda.taskito.worker.Worker;

Task<Map> add = Task.of("add", Map.class);

Queue queue = Taskito.builder().backend("sqlite").url("taskito.db").open();
Worker worker = queue.worker()
Taskito taskito = Taskito.builder().backend("sqlite").url("taskito.db").open();
Worker worker = taskito.worker()
.handle(add, p -> ((Number) p.get("a")).intValue() + ((Number) p.get("b")).intValue())
.concurrency(4)
.on(EventName.SUCCESS, e -> System.out.println("done: " + e.jobId))
Expand All @@ -60,7 +76,7 @@ Worker worker = queue.worker()
// exit to trigger close(), so it would deadlock.)
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
worker.close();
queue.close();
taskito.close();
}));
worker.awaitShutdown();
```
Expand All @@ -82,9 +98,9 @@ class EmailTasks {
}

// generated EmailTasksTasks:
String id = queue.enqueue(EmailTasksTasks.SEND, payload);
String id = taskito.enqueue(EmailTasksTasks.SEND, payload);

queue.worker()
taskito.worker()
.apply(b -> EmailTasksTasks.bind(b, new EmailTasks()))
.start();
```
Expand Down Expand Up @@ -114,9 +130,9 @@ Workflow wf = Workflow.named("etl")
.step("transform", transform, 2, "extract")
.step("load", load, 3, "transform");

WorkflowRun run = queue.submitWorkflow(wf);
WorkflowRun run = taskito.submitWorkflow(wf);

try (Worker worker = queue.worker()
try (Worker worker = taskito.worker()
.handle(extract, p -> p * 10)
.handle(transform, p -> p + 1)
.handle(load, p -> p)
Expand All @@ -139,7 +155,7 @@ Workflow etl = Workflow.named("etl")
.stepAfter("transform", transform, "extract")
.stepAfter("load", load, "transform");

queue.submitWorkflow(etl, Map.of("extract", 5, "transform", 6, "load", 7));
taskito.submitWorkflow(etl, Map.of("extract", 5, "transform", 6, "load", 7));
```

A step's effective payload is `map.get(name)` when present, else the one baked
Expand All @@ -163,7 +179,7 @@ gates, and sagas are not yet exposed.
### Middleware

```java
queue.use(new Middleware() {
taskito.use(new Middleware() {
@Override public void onEnqueue(EnqueueContext ctx) { /* validate / rewrite */ }
@Override public void before(TaskContext ctx) { /* trace */ }
@Override public void onDeadLetter(OutcomeEvent e) { /* alert */ }
Expand All @@ -183,7 +199,7 @@ try (DashboardServer dashboard = DashboardServer.start(queue, 8080, token, stati

```java
byte[] key = ...; // 16/24/32 bytes for AES
Queue secure = Taskito.builder()
Taskito secure = Taskito.builder()
.backend("sqlite").url("taskito.db")
.serializer(new EncryptedSerializer(new JsonSerializer(), key))
.open();
Expand All @@ -195,9 +211,10 @@ Packages are organized by feature; the root holds only the front door.

```text
org.byteveda.taskito
├── Taskito entry point — Taskito.builder()...open()
├── Queue public interface
├── DefaultQueue package-private impl (not exported)
├── Taskito client interface + entry — Taskito.builder()...open()
├── Queue named-queue handle (pause/resume) — Taskito.queue(name)
├── DefaultTaskito package-private client impl (not exported)
├── NamedQueue package-private Queue impl (not exported)
├── TaskitoException unchecked error type
├── task/ Task, TaskFunction, EnqueueOptions
├── model/ Job, JobStatus, QueueStats, DeadJob, JobError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.nio.file.Path;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.byteveda.taskito.Queue;
import org.byteveda.taskito.Taskito;
import org.byteveda.taskito.events.EventName;
import org.byteveda.taskito.scheduling.PeriodicTask;
Expand All @@ -25,7 +24,7 @@ public static void main(String[] args) throws Exception {
Path dir = Files.createTempDirectory("taskito-graalvm-smoke");
Task<String> echo = Task.of("echo", String.class);

try (Queue queue = Taskito.builder()
try (Taskito queue = Taskito.builder()
.backend("sqlite")
.url(dir.resolve("smoke.db").toString())
.open()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@
import org.byteveda.taskito.workflows.WorkflowStatus;

/**
* Default {@link Queue}: maps the typed public API onto a {@link QueueBackend},
* Default {@link Taskito}: maps the typed public API onto a {@link QueueBackend},
* serializing payloads with the configured {@link Serializer} and decoding
* native JSON views with a private mapper.
*/
final class DefaultQueue implements Queue {
final class DefaultTaskito implements Taskito {
private static final ObjectMapper VIEWS = new ObjectMapper();

private static final long DEFAULT_LOCK_TTL_MS = 30_000;
Expand All @@ -52,14 +52,19 @@ final class DefaultQueue implements Queue {
private final Serializer serializer;
private final List<Middleware> middleware = new CopyOnWriteArrayList<>();

DefaultQueue(QueueBackend backend, Serializer serializer) {
DefaultTaskito(QueueBackend backend, Serializer serializer) {
this.backend = backend;
this.facade = new CoreFacade(backend);
this.serializer = serializer;
}

@Override
public Queue use(Middleware middleware) {
public Queue queue(String name) {
return new NamedQueue(this, name);
}

@Override
public Taskito use(Middleware middleware) {
this.middleware.add(middleware);
return this;
}
Expand Down Expand Up @@ -236,13 +241,13 @@ public long purgeCompleted(long olderThanMs) {
return backend.purgeCompleted(olderThanMs);
}

@Override
public void pauseQueue(String queue) {
/** Pause one named queue; backs {@link NamedQueue#pause()}. */
void pauseLane(String queue) {
backend.pauseQueue(queue);
}

@Override
public void resumeQueue(String queue) {
/** Resume one named queue; backs {@link NamedQueue#resume()}. */
void resumeLane(String queue) {
backend.resumeQueue(queue);
}

Expand Down
32 changes: 32 additions & 0 deletions sdks/java/src/main/java/org/byteveda/taskito/NamedQueue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.byteveda.taskito;

/** Default {@link Queue}: scopes pause/resume to one named queue via its owning client. */
final class NamedQueue implements Queue {
private final DefaultTaskito owner;
private final String name;

NamedQueue(DefaultTaskito owner, String name) {
this.owner = owner;
this.name = name;
}

@Override
public String name() {
return name;
}

@Override
public void pause() {
owner.pauseLane(name);
}

@Override
public void resume() {
owner.resumeLane(name);
}

@Override
public boolean isPaused() {
return owner.listPausedQueues().contains(name);
}
}
Loading