Tardy
An asynchronous runtime for writing applications and services. Supports io_uring, epoll, kqueue, and poll for I/O.
Install / Use
/learn @tardy-org/TardyREADME
tardy
tardy (def: delaying or delayed beyond the right or expected time; late.) is an asynchronous runtime for writing applications and services in Zig. Most of the code for this project originated in zzz, a performance oriented networking framework.
- tardy utilizes the latest Asynchronous APIs while minimizing allocations.
- tardy natively supports Linux, Mac, BSD, and Windows.
- tardy is configurable, allowing you to optimize the runtime for your specific use-case.
Summary
tardy is a thread-local, I/O driven runtime for Zig, providing the core implementation for asynchronous libraries and services.
- Per-thread Runtime isolation for minimal contention
- Native async I/O (io_uring, epoll, kqueue, poll, etc.)
- Asynchronous
Sockets andFiles. - Coroutines (internally called Frames).
Installing
Compatible Zig Version: 0.15.2
Latest Release: 0.3.0
zig fetch --save git+https://github.com/tardy-org/tardy#v0.3.0
You can then add the dependency in your build.zig file:
const tardy = b.dependency("tardy", .{
.target = target,
.optimize = optimize,
}).module("tardy");
exe_mod.addImport("tardy", tardy);
Building and Running Examples
-
NOTE: by default build/install step uses
-Dexample=none, meaning it wont build any examples -
List available examples
zig build --help
- Build/run a specific example
zig build -Dexample=[nameOfExample]
zig build run -Dexample=[nameOfExample]
- Build all examples
zig build -Dexample=all
TCP Example
A basic multi-threaded TCP echo server.
const std = @import("std");
const AcceptResult = @import("tardy").AcceptResult;
const Cross = @import("tardy").Cross;
const Pool = @import("tardy").Pool;
const RecvResult = @import("tardy").RecvResult;
const Runtime = @import("tardy").Runtime;
const SendResult = @import("tardy").SendResult;
const Socket = @import("tardy").Socket;
const Task = @import("tardy").Task;
const Timer = @import("tardy").Timer;
const Tardy = @import("tardy").Tardy(.auto);
const log = std.log.scoped(.@"tardy/example/echo");
fn echo_frame(rt: *Runtime, server: *const Socket) !void {
const socket = try server.accept(rt);
defer socket.close_blocking();
var sock_reader = socket.reader(rt, &.{});
const sock_r = &sock_reader.interface;
var sock_writer = socket.writer(rt, &.{});
const sock_w = &sock_writer.interface;
defer sock_w.flush() catch unreachable;
log.debug(
"{d} - accepted socket [{f}]",
.{ std.time.milliTimestamp(), socket.addr },
);
// spawn off a new frame.
try rt.spawn(.{ rt, server }, echo_frame, 1024 * 16);
var buffer: [501]u8 = undefined;
while (true) {
const recv_length = sock_r.readSliceShort(&buffer) catch |e| {
log.err("Failed to recv on socket | {t}", .{e});
break;
};
if (recv_length == 0) return;
sock_w.writeAll(buffer[0..recv_length]) catch |e| {
log.err("Failed to send on socket | {t}", .{e});
break;
};
log.debug("Echoed: {s}", .{buffer[0..recv_length]});
}
}
pub fn main() !void {
var gpa: std.heap.DebugAllocator(.{}) = .init;
const allocator = gpa.allocator();
defer _ = gpa.deinit();
var tardy: Tardy = try .init(allocator, .{
.threading = .single,
.pooling = .static,
.size_tasks_initial = 256,
.size_aio_reap_max = 256,
});
defer tardy.deinit();
const host = "0.0.0.0";
const port = 9862;
const server: Socket = try .init(.{ .tcp = .{ .host = host, .port = port } });
try server.bind();
try server.listen(1024);
try tardy.entry(
&server,
struct {
fn start(rt: *Runtime, tcp_server: *const Socket) !void {
try rt.spawn(.{ rt, tcp_server }, echo_frame, 1024 * 16);
}
}.start,
);
}
There exist a lot more examples, highlighting a variety of use cases and features here. For an example of tardy in use, you can check out any of the projects in the ecosystem.
Ecosystem
- zzz: a framework for writing performant and reliable networked services.
- secsock: Async TLS for the Tardy Socket.
Contribution
We use Nix Flakes for managing the development environment. Nix Flakes provide a reproducible, declarative approach to managing dependencies and development tools.
Prerequisites
- Install Nix
sh <(curl -L https://nixos.org/nix/install) --daemon
- Enable Flake support in your Nix config (
~/.config/nix/nix.conf):experimental-features = nix-command flakes
Getting Started
- Clone this repository:
git clone https://github.com/tardy-org/tardy.git
cd tardy
- Enter the development environment:
nix develop
This will provide you with a shell that contains all of the necessary tools and dependencies for development.
Once you are inside of the development shell, you can update the development dependencies by:
- Modifying the
flake.nix - Running
nix flake update - Committing both the
flake.nixand theflake.lock
License
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in tardy by you, shall be licensed as MPL2.0, without any additional terms or conditions.
Related Skills
openhue
354.5kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
354.5kElevenLabs text-to-speech with mac-style say UX.
weather
354.5kGet current weather and forecasts via wttr.in or Open-Meteo
casdoor
13.3kAn open-source AI-first Identity and Access Management (IAM) /AI MCP & agent gateway and auth server with web UI supporting OpenClaw, MCP, OAuth, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA, Face ID, Google Workspace, Azure AD
