{"id":45759694,"url":"https://github.com/iopsystems/durable","last_synced_at":"2026-02-25T22:12:43.437Z","repository":{"id":253324314,"uuid":"843159584","full_name":"iopsystems/durable","owner":"iopsystems","description":"A durable execution engine for rust ","archived":false,"fork":false,"pushed_at":"2026-02-17T23:37:49.000Z","size":947,"stargazers_count":39,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-17T23:53:55.712Z","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":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iopsystems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","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":"2024-08-15T23:01:12.000Z","updated_at":"2026-02-17T23:37:52.000Z","dependencies_parsed_at":"2024-08-29T22:51:49.523Z","dependency_job_id":"07978ec0-5157-4725-9d79-89c8c18bfaaa","html_url":"https://github.com/iopsystems/durable","commit_stats":null,"previous_names":["iopsystems/durable"],"tags_count":64,"template":false,"template_full_name":null,"purl":"pkg:github/iopsystems/durable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iopsystems%2Fdurable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iopsystems%2Fdurable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iopsystems%2Fdurable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iopsystems%2Fdurable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iopsystems","download_url":"https://codeload.github.com/iopsystems/durable/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iopsystems%2Fdurable/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29843294,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-25T21:18:31.832Z","status":"ssl_error","status_checked_at":"2026-02-25T21:18:29.265Z","response_time":61,"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-02-25T22:12:42.496Z","updated_at":"2026-02-25T22:12:43.429Z","avatar_url":"https://github.com/iopsystems.png","language":"Rust","readme":"# Durable\n\nDurable is durable execution engine. You write a workflow and durable takes care\nof running it to completion, regardless of whether your application is restarted,\nupdated, or otherwise becomes unavailable while it is running.\n\n## Features\n- Reliably runs workflows to completion, even if the host running the workflow\n  is interrupted while it is running.\n- Supports running the worker embedded within an existing application.\n- Provides at-least-once semantics for external effects by workflows and\n  exactly-once semantics for changes made to the database that is being used\n  by the worker.\n\n## Getting started\nTo try it out locally, run\n\n```bash\n# First, start up a postgresql database for durable to use.\ncargo xtask dev -d\n\ncargo run --bin durable-worker --features cli -- \\\n    --database-url postgres://postgres@localhost:5432/postgres \\\n    --migrate\n```\n\nNow, in another terminal, build the example workflows. \n\n\u003e To do this you will need to have installed `cargo-component`.\n\u003e\n\u003e ```bash\n\u003e cargo install --locked cargo-component\n\u003e ```\n\n```bash\ncargo component build --examples --features sqlx,http --profile wasm\n```\n\nNow, you can run it on the worker we created above.\n```bash\ncargo run --bin durable -- launch \\\n    --database-url postgres://postgres@localhost:5432/postgres \\\n    --tail \\\n    'my first task' target/wasm32-wasip1/wasm/examples/hello-world.wasm\n```\n\nThis should then output\n```\nHello, my first task!\n```\n\nYou can see more of what can be done with durable by looking at the examples in\nthe [`examples`](examples) crate.\n\n## Writing a Workflow\nDurable workflows are wasm components that use WASI to interact with the durable\nruntime. In practice, this means that you write a small rust program that uses\nthe [`durable`] crate and then compile that to a wasm component by using\n`cargo-component`.\n\nLet's do just that!\n\nHere is our workflow:\n```rust\nuse std::net::IpAddr;\nuse serde::Deserialize;\n\n#[derive(Deserialize)]\nstruct Ip {\n    origin: IpAddr\n}\n\nfn main() {\n    let response = durable::http::get(\"https://httpbin.org/ip\")\n        .send()\n        .expect(\"failed to send an HTTP request\");\n    let response: Ip = response\n        .json()\n        .expect(\"response contained unexpected JSON\");\n\n    println!(\"This workflow was run at {}\", response.origin);\n}\n```\n\nAll this workflow does is make a request to \u003chttps://httpbin.org/ip\u003e, which\nreturns the IP address of the host that made the request.\n\nHere's the `Cargo.toml` we'll need. Note that we need the `http` feature of\ndurable.\n\n```toml\n[package]\nname = \"example-http\"\nversion = \"0.0.0\"\nedition = \"2021\"\n\n[dependencies]\nserde = { version = \"1.0\", features = [\"derive\"] }\n\n[dependencies.durable]\ngit = \"https://github.com/iopsystems/durable\"\nfeatures = [\"http\"]\n```\n\nNow we can build our crate by running `cargo-component`:\n```bash\ncargo component --bin example-http\n```\n\nThis will give us a wasm binary that we can then run on a durable worker using\nthe `durable` command:\n```bash\ndurable launch --tail 'http example' target/wasm32-wasip1/example-http.wasm \\\n    --database-url postgres://your/database\n```\n\nNote that you will need to have a worker running on the same postgres database\nin order for the task to run.\n\n## How it works\nAt its basic level, durable works by recording the outcomes of any external\neffects performed by a workflow. If you make an HTTP request, or a database\ntransaction, then the results of that operation gets saved as an event in the\ndatabase. If the workflow ever gets interrupted it will be restarted on a\ndifferent worker. However, this time, instead of redoing the external effects\nthat have already been done it will return the saved results from the first\nexecution within the event log.\n\nTo illustrate this, lets consider a workflow that looks like this:\n```rust\nuse std::time::Duration;\n\nfn main() -\u003e anyhow::Result\u003c()\u003e {\n    let response = durable::http::get(\"https://example.com\").send()?;\n    \n    std::thread::sleep(Duration::from_secs(10));\n\n    println!(\"Got response:\\n{}\", response.text());\n\n    Ok(())\n}\n```\n\nIf this runs normally, without being interrupted, then the event log at the\nend might look something like this:\n```text\nidx | event         | data\n0   | http/send     | HTTP/1.1 200 OK ...\n1   | now           | 10293101412\n2   | sleep_until   |\n3   | write         | 2031\n```\n\nWe can see the task making the HTTP request, getting the current time, sleeping,\nand then writing to the log. At each point, it records what the result of that\noperation to the event log.\n\nSuppose, now, that instead of running until the end, the worker running the\nworkflow dies during the call to `sleep_until`. When this happens, the event\nlog looks like this:\n```text\nidx | event         | data\n0   | http/send     | HTTP/1.1 200 OK ...\n1   | now           | 10293101412\n```\n\nSome other worker picks up the workflow and starts running it from the top.\nHowever, something is different this time around, when the workflow makes the\nHTTP request it looks at the event log and sees the previous entry recorded\nwithin. Instead of doing the HTTP request again, it just reads the response\nfrom last time and returns that. The same happens with the call to `now`.\n\nNow that the workflow has reached where it was interrupted before we can\ncontinue where we left off before. Since the workflow is sandboxed, and\nexternal function calls are recorded, workflow execution is\ndeterministic[^1]. This means that this new execution of the workflow should\nbe in the same state as the previous one was killed within.\n\n[^1]: By using interior mutability and some more advanced features of the\n      durable crate it is possible to break this, which would result in\n      executions that differ from each other. This is not easy to do\n      accidentally, though, so is usually not an issue.\n","funding_links":[],"categories":["\u003ca name=\"Rust\"\u003e\u003c/a\u003eRust"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiopsystems%2Fdurable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiopsystems%2Fdurable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiopsystems%2Fdurable/lists"}