Skip to content

An asynchronous runtime for writing applications and services. Supports io_uring, epoll, kqueue, and poll for I/O.

License

Notifications You must be signed in to change notification settings

tardy-org/tardy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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.

Discord

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 and Files.
  • Coroutines (internally called Frames).

Installing

Compatible Zig Version: 0.13.0

Latest Release: 0.2.1

zig fetch --save git+https://github.com/tardy-org/tardy#v0.2.1

You can then add the dependency in your build.zig file:

const tardy = b.dependency("tardy", .{
    .target = target,
    .optimize = optimize,
}).module("tardy");

exe.root_module.addImport(tardy);

Example

A basic multi-threaded TCP echo server.

const std = @import("std");
const log = std.log.scoped(.@"tardy/example/echo");

const Pool = @import("tardy").Pool;
const Runtime = @import("tardy").Runtime;
const Task = @import("tardy").Task;
const Tardy = @import("tardy").Tardy(.auto);
const Cross = @import("tardy").Cross;

const Socket = @import("tardy").Socket;
const Timer = @import("tardy").Timer;

const AcceptResult = @import("tardy").AcceptResult;
const RecvResult = @import("tardy").RecvResult;
const SendResult = @import("tardy").SendResult;

fn echo_frame(rt: *Runtime, server: *const Socket) !void {
    const socket = try server.accept(rt);
    defer socket.close_blocking();

    // you can use the standard Zig Reader/Writer if you want!
    const reader = socket.reader(rt);
    const writer = socket.writer(rt);

    log.debug(
        "{d} - accepted socket [{}]",
        .{ std.time.milliTimestamp(), socket.addr },
    );

    try rt.spawn(.{ rt, server }, echo_frame, 1024 * 16);

    var buffer: [1024]u8 = undefined;
    while (true) {
        const recv_length = reader.read(&buffer) catch |e| {
            log.err("Failed to recv on socket | {}", .{e});
            return;
        };

        writer.writeAll(buffer[0..recv_length]) catch |e| {
            log.err("Failed to send on socket | {}", .{e});
            return;
        };

        log.debug("Echoed: {s}", .{buffer[0..recv_length]});
    }
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    defer _ = gpa.deinit();

    // tardy by default is 
    // - multithreaded
    // - unbounded in terms of spawnable tasks
    var tardy = try Tardy.init(allocator, .{});
    defer tardy.deinit();

    const server = try Socket.init(.{ .tcp = .{ .host = "127.0.0.1", .port = 9862 } });
    try server.bind();
    try server.listen(256);

    try tardy.entry(
        &server,
        struct {
            fn start(rt: *Runtime, tcp_server: *const Socket) !void {
                try rt.spawn(.{ rt, tcp_server }, echo_frame, 1024 * 1024 * 4);
            }
        }.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.

Contribution

We use Nix Flakes for managing the development environment. Nix Flakes provide a reproducible, declarative approach to managing dependencies and development tools.

Prerequisites

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

  1. Clone this repository:
git clone https://github.com/tardy-org/tardy.git
cd tardy
  1. 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:

  1. Modifying the flake.nix
  2. Running nix flake update
  3. Committing both the flake.nix and the flake.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.