Java Client
dev.quicx:quicx-client is a small, dependency-free Java 11+ library. Two classes carry the whole surface area: QuicxClient for producers, QuicxWorker for consumers.
Add it to your build
<dependency>
<groupId>dev.quicx</groupId>
<artifactId>quicx-client</artifactId>
<version>1.0.0</version>
</dependency>QuicxClient — producers
QuicxClient is stateless at the connection level: every call to submit()opens a fresh TCP connection, performs the submit request-reply, and closes. Keep the object around for the lifetime of the producer — it’s safe to reuse and share across threads.
- new QuicxClient(host, port)
- Construct a reusable handle. No network work is performed here.
- int submit(type, byte[])
- Send a
MSG_SUBMITwith a raw payload. Returns the 32-bit task id assigned by the daemon. ThrowsQuicxExceptiononMSG_ERROR. - int submit(type, String)
- Convenience overload: UTF-8 encodes the payload for you.
- close()
- Idempotent. Tears down any transport resources. Use try-with-resources.
import dev.quicx.QuicxClient;
import dev.quicx.QuicxException;
try (QuicxClient client = new QuicxClient("localhost", 16381)) {
int id = client.submit(
"resize_image",
new byte[]{ 0x01, 0x02, 0x03 /* raw bytes */ }
);
System.out.println("accepted id = " + id);
} catch (QuicxException e) {
System.err.println("rejected: " + e.getMessage());
}QuicxWorker — consumers
QuicxWorker is a long-lived connection that receives MSG_TASK frames. Register a handler per task type; the worker dispatches by string key and replies to the daemon with MSG_DONE or MSG_FAILED automatically.
- new QuicxWorker(host, port)
- Construct a worker. No network work happens until start().
- handle(type, handler)
- Register a
TaskHandlerfor a task type. Returnsthisfor chaining. - start()
- Connect, send
MSG_READYand enter the dispatch loop. Blocks forever. On an unexpected disconnect the worker sleeps for 3 s and reconnects. - close()
- Flips the running flag, closes the socket and unblocks start(). Safe to call from a shutdown hook.
import dev.quicx.QuicxWorker;
public class Worker {
public static void main(String[] args) throws Exception {
QuicxWorker worker = new QuicxWorker("localhost", 16381)
.handle("send_email", payload -> {
String body = new String(payload, "UTF-8");
EmailService.deliver(body);
})
.handle("resize_image", payload -> {
Images.resize(payload);
});
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try { worker.close(); } catch (Exception ignored) {}
}));
worker.start(); // blocks — the dispatch loop owns this thread
}
}MSG_FAILED with exception.getMessage() as the reason — the task is not retried automatically. If no handler is registered for an incoming type, the worker logs and sends MSG_FAILED with “no handler for: …”.QuicxException
An unchecked RuntimeException thrown by QuicxClient#submiton rejection or protocol error. It wraps the daemon’s MSG_ERROR message string so the cause is visible without decoding bytes by hand.
package dev.quicx;
public class QuicxException extends RuntimeException {
public QuicxException(String message) { super(message); }
public QuicxException(String message, Throwable cause) {
super(message, cause);
}
}