{"id":48760702,"url":"https://github.com/paulosuzart/zart","last_synced_at":"2026-04-22T20:30:45.674Z","repository":{"id":350687385,"uuid":"1201506146","full_name":"paulosuzart/zart","owner":"paulosuzart","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-11T15:35:43.000Z","size":1175,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-11T16:25:28.063Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paulosuzart.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-04T19:12:54.000Z","updated_at":"2026-04-11T15:35:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/paulosuzart/zart","commit_stats":null,"previous_names":["paulosuzart/zart"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/paulosuzart/zart","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulosuzart%2Fzart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulosuzart%2Fzart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulosuzart%2Fzart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulosuzart%2Fzart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulosuzart","download_url":"https://codeload.github.com/paulosuzart/zart/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulosuzart%2Fzart/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32154680,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T17:06:48.269Z","status":"ssl_error","status_checked_at":"2026-04-22T17:06:19.037Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-13T06:00:40.904Z","updated_at":"2026-04-22T20:30:45.666Z","avatar_url":"https://github.com/paulosuzart.png","language":"Rust","funding_links":[],"categories":["\u003ca name=\"Rust\"\u003e\u003c/a\u003eRust"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"webpage/src/assets/logo-dark.svg\"\u003e\n    \u003cimg alt=\"Zart logo\" src=\"webpage/src/assets/logo-light.svg\" width=\"120\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n# Zart\n\n\u003e **Durable execution for Rust.** Write workflows that survive crashes, restarts, and redeployments — without losing progress or repeating work.\n\n**⚠️ Alpha — Work in Progress.** Zart is actively developed and not yet production-ready. Expect API changes and missing features.\n\n---\n\n## Why Zart Exists\n\nAcross payment processing, content generation, user onboarding, and compliance workflows, the same pattern repeats: teams build unreliable systems not because they don't care, but because the industry normalized a false choice. Ship fast and patch reliability later, or adopt heavy orchestration infrastructure from day one.\n\nThe tools that solve this — Temporal, Cadence, and similar platforms — are powerful. But they introduce concepts, infrastructure, and learning curves that most teams aren't ready for on day one. So reliability becomes a \"later\" problem. Until \"later\" means revenue loss, customer churn, or regulatory risk.\n\n**Zart exists so you don't have to learn that lesson.**\n\nIt's a Rust library designed for **high ergonomics and zero orchestration overhead**. You get durable execution using your existing PostgreSQL database — no new infrastructure, no distributed systems primitives, no paradigm shift.\n\n---\n\n## What is Durable Execution?\n\nDurable execution lets you write long-running workflows as ordinary async Rust code. Each step is checkpointed to the database. If your process crashes, times out, or gets redeployed, Zart resumes from the last successful step — no work is lost, no step is repeated.\n\nThink of it like GitHub Actions: your workflow has multiple steps, and if the infrastructure fails mid-run, it resumes where it left off. No one configures durability as a non-functional requirement — it's just how the platform works. Zart brings that same default-reliable experience to your Rust backend.\n\n## Complete Example\n\nAn order fulfillment workflow that validates an address, processes payment, then waits for an external shipment event:\n\n```rust\nuse zart::prelude::*;\nuse zart::{zart_durable, zart_step};\nuse zart::error::TaskError;\nuse serde::{Deserialize, Serialize};\nuse std::time::Duration;\n\n// ── Input / Output / Events ───────────────────────────────────────────────────\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\nstruct OrderInput {\n    order_id: String,\n    amount: f64,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\nstruct Receipt {\n    order_id: String,\n    transaction_id: String,\n    tracking_number: String,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\nstruct ShipmentEvent {\n    tracking_number: String,\n}\n\n// ── Step error types ──────────────────────────────────────────────────────────\n\n#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]\nenum PaymentError {\n    #[error(\"card declined: {reason}\")]\n    CardDeclined { reason: String },\n}\n\n// ── Step 1: Validate address ──────────────────────────────────────────────────\n\n#[zart_step(\"validate-address\")]\nasync fn validate_address(order_id: String) -\u003e Result\u003cString, PaymentError\u003e {\n    // ... call address validation service ...\n    Ok(format!(\"addr-{order_id}\"))\n}\n\n// ── Step 2: Process payment ───────────────────────────────────────────────────\n// Retries up to 3 times with exponential backoff on transient failures.\n\n#[zart_step(\"process-payment\", retry = \"exponential(3, 2s)\")]\nasync fn process_payment(order_id: String, amount: f64) -\u003e Result\u003cString, PaymentError\u003e {\n    // ... call payment service ...\n    Ok(format!(\"txn-{order_id}\"))\n}\n\n// ── Step 3: Reserve inventory ─────────────────────────────────────────────────\n\n#[zart_step(\"reserve-inventory\")]\nasync fn reserve_inventory(order_id: String) -\u003e Result\u003c(), PaymentError\u003e {\n    // ... call inventory service ...\n    Ok(())\n}\n\n// ── Durable workflow ──────────────────────────────────────────────────────────\n\n#[zart_durable(\"order-fulfillment\", timeout = \"30m\")]\nasync fn order_fulfillment(data: OrderInput) -\u003e Result\u003cReceipt, TaskError\u003e {\n    validate_address(data.order_id.clone()).await?;\n    let txn_id = process_payment(data.order_id.clone(), data.amount).await?;\n    reserve_inventory(data.order_id.clone()).await?;\n\n    // Durable sleep — survives restarts, no threads blocked\n    zart::sleep(\"warehouse-settle\", Duration::from_secs(60)).await?;\n\n    // Wait up to 1 hour for an external \"shipment_ready\" event\n    let event: ShipmentEvent = zart::wait_for_event(\n        \"shipment_ready\",\n        Some(Duration::from_secs(3600)),\n    ).await?;\n\n    Ok(Receipt {\n        order_id: data.order_id,\n        transaction_id: txn_id,\n        tracking_number: event.tracking_number,\n    })\n}\n```\n\nIf the process crashes after `process_payment` completes, a restart skips that step and resumes from `reserve_inventory`. No double-charges.\n\n---\n\n## What You Get\n\n| Feature | What it does |\n|---|---|\n| **Step checkpointing** | Every step result persists to PostgreSQL. Crashes resume, not restart. |\n| **Retry policies** | Per-step fixed or exponential backoff. Configurable attempts and delay. |\n| **Durable sleep** | Pause workflows for minutes, hours, or days. Zero threads blocked. |\n| **Event-driven waits** | Suspend until an external signal arrives — human approval, webhook, callback. |\n| **Parallel steps** | Fan out independent work, wait for all to complete. Survives restarts mid-wait. |\n| **Durable loops** | Iterate over collections with per-iteration checkpoints. Restarts skip done items. |\n| **No new infrastructure** | Uses the PostgreSQL database you already have. Workers poll via `SKIP LOCKED`. |\n\n## Philosophy\n\n- **Reliability from day one** — Every step persists its result. Failures resume, not restart.\n- **No new infrastructure** — Uses the PostgreSQL database you already have.\n- **Progressive complexity** — Start simple. Add retries, parallel steps, and events only when you need them.\n- **Rust-native** — Built on `tokio`, `serde`, and standard Rust patterns. No alien mental models.\n- **Zero vendor lock-in** — It's a library, not a platform. Your workflows are just Rust code.\n\n## Who Zart Is For\n\n- **Teams shipping workflows** — payment flows, onboarding pipelines, content generation, data processing — that can't afford to lose progress.\n- **Engineers who want reliability** without adopting a full orchestration platform or learning a new paradigm.\n- **Startups and scale-ups** that need to move fast but can't afford to rebuild workflows after every incident.\n\n## Who Zart Is Not For\n\n- **Massive workflow orchestration** — If you're coordinating thousands of workers across multiple regions, Temporal or a similar platform may be a better fit.\n- **Teams that need a managed service** — Zart is self-hosted on your infrastructure. There's no Zart Cloud (yet).\n\n---\n\n## Getting Started\n\nFull documentation, examples, and API reference live at **[zart.run](http://zart.run/)**.\n\n- **[Getting Started](http://zart.run/getting-started/)** — installation and your first workflow\n- **[Features](http://zart.run/features/)** — steps, retries, sleep, events, and parallel execution\n- **[Examples](http://zart.run/examples/)** — real-world patterns (brewery finder, approval workflows, parallel steps)\n- **[Rust API](http://zart.run/rust-api/overview/)** — `#[zart_step]`, `#[zart_durable]`, macros, and loops\n\n### In Your Project\n\n```toml\n[dependencies]\nzart = \"0.1\"\nzart-macros = \"0.1\"\n```\n\n```bash\n# Start PostgreSQL\ndocker compose up -d\n\n# Run migrations\njust migrate\n\n# Run the sleep example\njust example-sleep\n```\n\n## Project Structure\n\n| Crate | Description |\n|---|---|\n| `zart` | Core durable execution library |\n| `scheduler` | PostgreSQL-backed task scheduler \u0026 worker |\n| `zart-cli` | Command-line tools |\n| `zart-api` | HTTP API for external event delivery |\n| `zart-macros` | Procedural macros (`#[zart_step]`, `#[zart_durable]`) |\n\n## Architecture\n\nZart uses a pull-based model: workers poll PostgreSQL for due tasks and execute them. No coordinator service is required beyond your existing worker processes.\n\nSteps are decomposed into:\n1. **Body mode** — your workflow function schedules/looks up steps\n2. **Step mode** — individual step lambdas execute\n3. **Completion** — results are atomically persisted and the next body task is scheduled\n\nAll state lives in PostgreSQL tables (`zart_tasks`, `zart_steps`, `zart_step_attempts`, `zart_execution_runs`).\n\n## Development\n\n```bash\n# Start PostgreSQL\ndocker compose up -d\n\n# Run tests\njust test\n\n# Lint \u0026 format\njust lint\njust fmt\n```\n\n## License\n\nMIT\n\n## Links\n\n- **[Website](http://zart.run/)** — full documentation and examples\n- **[GitHub](https://github.com/paulosuzart/zart)** — source code and issues\n- **[About](http://zart.run/about/)** — the story and philosophy behind Zart\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulosuzart%2Fzart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulosuzart%2Fzart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulosuzart%2Fzart/lists"}