{"id":13478811,"url":"https://github.com/softwaremill/ox","last_synced_at":"2025-05-15T20:01:37.947Z","repository":{"id":137884447,"uuid":"590486587","full_name":"softwaremill/ox","owner":"softwaremill","description":"Safe direct-style concurrency and resiliency for Scala on the JVM","archived":false,"fork":false,"pushed_at":"2025-03-19T00:31:11.000Z","size":1320,"stargazers_count":422,"open_issues_count":17,"forks_count":29,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-04-01T01:37:52.270Z","etag":null,"topics":["channels","concurrency","goroutines","jvm","loom","scala","structured-concurrency","virtual-threads"],"latest_commit_sha":null,"homepage":"https://ox.softwaremill.com","language":"Scala","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/softwaremill.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2023-01-18T14:28:30.000Z","updated_at":"2025-03-24T23:38:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"9c6da939-666e-41d6-96d6-287656c83876","html_url":"https://github.com/softwaremill/ox","commit_stats":{"total_commits":509,"total_committers":25,"mean_commits":20.36,"dds":"0.32023575638506874","last_synced_commit":"37240fd65eda69ef32a21f3eb2f444ef0fa7f6c6"},"previous_names":[],"tags_count":57,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/softwaremill","download_url":"https://codeload.github.com/softwaremill/ox/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247766205,"owners_count":20992430,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["channels","concurrency","goroutines","jvm","loom","scala","structured-concurrency","virtual-threads"],"created_at":"2024-07-31T16:02:03.643Z","updated_at":"2025-04-08T02:38:10.606Z","avatar_url":"https://github.com/softwaremill.png","language":"Scala","readme":"# Ox\n\n[![Ideas, suggestions, problems, questions](https://img.shields.io/badge/Discourse-ask%20question-blue)](https://softwaremill.community/c/ox)\n[![CI](https://github.com/softwaremill/ox/workflows/CI/badge.svg)](https://github.com/softwaremill/ox/actions?query=workflow%3A%22CI%22)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.softwaremill.ox/core_3/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.softwaremill.ox/core_3)\n\nSafe direct-style concurrency and resiliency for Scala on the JVM. Requires JDK 21 \u0026 Scala 3. The areas that we'd like \nto cover with Ox are:\n\n* concurrency: developer-friendly structured concurrency, high-level concurrency operators, safe low-level primitives, \n  communication between concurrently running computations\n* error management: retries, timeouts, a safe approach to error propagation, safe resource management\n* scheduling \u0026 timers\n* resiliency: circuit breakers, bulkheads, rate limiters, backpressure\n\nAll of the above should allow for observability of the orchestrated business logic. We aim to enable writing simple, \nexpression-oriented code in functional style. We’d like to keep the syntax overhead to a minimum, preserving \ndeveloper-friendly stack traces, and without compromising performance.\n\nSome of the above are already addressed in the API, some are coming up in the future. We’d love your help in shaping \nthe project!\n\nTo test Ox, use the following dependency, using either [sbt](https://www.scala-sbt.org):\n\n```scala\n\"com.softwaremill.ox\" %% \"core\" % \"0.5.13\"\n```\n\nOr [scala-cli](https://scala-cli.virtuslab.org):\n\n```scala\n//\u003e using dep \"com.softwaremill.ox::core:0.5.13\"\n```\n\nDocumentation is available at [https://ox.softwaremill.com](https://ox.softwaremill.com), ScalaDocs can be browsed at [https://javadoc.io](https://www.javadoc.io/doc/com.softwaremill.ox).\n\n## Tour of ox\n\nRun two computations [in parallel](https://ox.softwaremill.com/latest/high-level-concurrency/par.html):\n\n```scala mdoc:compile-only\ndef computation1: Int = { sleep(2.seconds); 1 }\ndef computation2: String = { sleep(1.second); \"2\" }\nval result1: (Int, String) = par(computation1, computation2)\n// (1, \"2\")\n```\n\n[Timeout](https://ox.softwaremill.com/latest/high-level-concurrency/timeout.html) a computation:\n\n```scala mdoc:compile-only\ndef computation3: Int = { sleep(2.seconds); 1 }\nval result2: Either[Throwable, Int] = either.catching(timeout(1.second)(computation3))\n// `timeout` only completes once the loosing branch is interrupted \u0026 done\n```\n\n[Race](https://ox.softwaremill.com/latest/high-level-concurrency/race.html) two computations:\n\n```scala mdoc:compile-only\ndef computation4: Int = { sleep(2.seconds); 1 }\ndef computation5: Int = { sleep(1.second); 2 }\nval result3: Int = raceSuccess(computation4, computation5)\n// as before, the loosing branch is interrupted \u0026 awaited before returning a result\n```\n\n[Structured concurrency](https://ox.softwaremill.com/latest/structured-concurrency/fork-join.html) \u0026 supervision:\n\n```scala mdoc:compile-only\n// equivalent of par\nsupervised {\n  val f1 = fork { sleep(2.seconds); 1 }\n  val f2 = fork { sleep(1.second); 2 }\n  (f1.join(), f2.join())\n}\n```\n\nError handling within a structured concurrency scope:\n\n```scala mdoc:compile-only\nsupervised {\n  forkUser:\n    sleep(1.second)\n    println(\"Hello!\")\n\n  forkUser:\n    sleep(500.millis)\n    throw new RuntimeException(\"boom!\")\n}\n// on exception, all other forks are interrupted (\"let it crash\")\n// the scope ends \u0026 re-throws only when all forks complete (no \"leftovers\")\n```\n\n[Retry](https://ox.softwaremill.com/latest/utils/retries.html) a computation:\n\n```scala mdoc:compile-only\ndef computationR: Int = ???\nretry(RetryConfig.backoff(3, 100.millis, 5.minutes, Jitter.Equal))(computationR)\n```\n\n[Repeat](https://ox.softwaremill.com/latest/utils/repeat.html) a computation:\n\n```scala mdoc:compile-only\ndef computationR: Int = ???\nrepeat(RepeatConfig.fixedRateForever(100.millis))(computationR)\n```\n\n[Rate limit](https://ox.softwaremill.com/latest/utils/rate-limiter.html) computations:\n\n```scala mdoc:compile-only\nsupervised:\n  val rateLimiter = RateLimiter.fixedWindowWithStartTime(2, 1.second)\n  rateLimiter.runBlocking({ /* ... */ })\n```\n\nAllocate a [resource](https://ox.softwaremill.com/latest/utils/resources.html) in a scope:\n\n```scala mdoc:compile-only\nsupervised {\n  val writer = useCloseableInScope(new java.io.PrintWriter(\"test.txt\"))\n  // ... use writer ...\n} // writer is closed when the scope ends (successfully or with an error)\n```\n\n[Create an app](https://ox.softwaremill.com/latest/utils/oxapp.html) which shuts down cleanly when interrupted with SIGINT/SIGTERM:\n\n```scala mdoc:compile-only\nobject MyApp extends OxApp:\n  def run(args: Vector[String])(using Ox): ExitCode =\n    // ... your app's code ...\n    // might use fork {} to create top-level background threads\n    ExitCode.Success\n```\n\nSimple type-safe [actors](https://ox.softwaremill.com/latest/utils/actors.html):\n\n```scala mdoc:compile-only\nclass Stateful { def increment(delta: Int): Int = ??? }\n\nsupervised:\n  val ref = Actor.create(new Stateful)\n  // ref can be shared across forks, but only within the concurrency scope\n  ref.ask(_.increment(5))    \n```\n\nCreate a simple [flow](https://ox.softwaremill.com/latest/streaming/flows.html) \u0026 transform using a functional API:\n\n```scala mdoc:compile-only\nFlow.iterate(0)(_ + 1) // natural numbers\n  .filter(_ % 2 == 0)\n  .map(_ + 1)\n  .intersperse(5)\n  // compute the running total\n  .mapStateful(0) { (state, value) =\u003e\n    val newState = state + value\n    (newState, newState)\n  }\n  .take(10)\n  .runForeach(n =\u003e println(n.toString))\n```\n\nCreate flows which perform I/O and manage concurrency:\n\n```scala mdoc:compile-only\ndef sendHttpRequest(entry: String): Unit = ???\nFlow\n  .fromInputStream(this.getClass().getResourceAsStream(\"/list.txt\"))\n  .linesUtf8\n  .mapPar(4)(sendHttpRequest)\n  .runDrain()\n```\n\nMerge two flows, properly handling the failure of either branches:\n\n```scala mdoc:compile-only\nval f1 = Flow.tick(123.millis, \"left\")\nval f2 = Flow.tick(312.millis, \"right\")\nf1.merge(f2).take(100).runForeach(println)\n```\n\nIntegrate flow with other components using an imperative API:\n\n```scala mdoc:compile-only\ndef readNextBatch(): List[String] = ???\nFlow.usingEmit { emit =\u003e\n  forever:\n    readNextBatch().foreach(emit.apply)\n}\n```\n\nUse completable high-performance [channels](https://ox.softwaremill.com/latest/streaming/channels.html) for inter-fork communication within concurrency scopes:\n\n```scala mdoc:compile-only\nval c = Channel.buffered[String](8)\nc.send(\"Hello,\")\nc.send(\"World\")\nc.done()\n```\n\n[Select](https://ox.softwaremill.com/latest/streaming/selecting-from-channels.html) from Go-like channels:\n\n```scala mdoc:compile-only\nval c = Channel.rendezvous[Int]\nval d = Channel.rendezvous[Int]\nselect(c.sendClause(10), d.receiveClause)\n```\n\n[Unwrap eithers](https://ox.softwaremill.com/latest/basics/error-handling.html) and combine errors in a union type:\n\n```scala mdoc:compile-only\nval v1: Either[Int, String] = ???\nval v2: Either[Long, String] = ???\n\nval result: Either[Int | Long, String] = either:\n  v1.ok() ++ v2.ok()\n```\n\n[Pipe \u0026 tap](https://ox.softwaremill.com/latest/utils/control-flow.html) values to functions to use the dot-syntax:\n\n```scala mdoc:compile-only\ndef compute: Int = ???\ndef computeMore(v: Int): Long = ???\ncompute\n  .pipe(2 * _)\n  .tap(println)\n  .pipe(computeMore)  \n```\n\nMore [in the docs!](https://ox.softwaremill.com).\n\n## Other projects\n\nThe wider goal of direct-style Scala is enabling teams to deliver working software quickly and with confidence. Our\nother projects, including [sttp client](https://sttp.softwaremill.com) and [tapir](https://tapir.softwaremill.com),\nalso include integrations directly tailored towards direct style.\n\nMoreover, also check out the [gears](https://github.com/lampepfl/gears) project, an experimental multi-platform library\nalso covering direct-style Scala.\n\n## Contributing\n\nAll suggestions welcome :)\n\nTo compile and test, run:\n\n```\nsbt compile\nsbt test\n```\n\nSee the list of [issues](https://github.com/softwaremill/ox/issues) and pick one! Or report your own.\n\nIf you are having doubts on the _why_ or _how_ something works, don't hesitate to ask a question on\n[discourse](https://softwaremill.community/c/ox) or via github. This probably means that the documentation, ScalaDocs or\ncode is unclear and can be improved for the benefit of all.\n\nIn order to develop the documentation, you can use the `doc/watch.sh` script, which runs Sphinx using Python.\nUse `doc/requirements.txt` to set up your Python environment with `pip`. \nAlternatively, if you're a Nix user, run `nix develop` in `doc/` to start a shell with an environment allowing to run `watch.sh`.\nMoreover, you can use the `compileDocumentation` sbt task to verify, that all code snippets compile properly.\n\nWhen you have a PR ready, take a look at our [\"How to prepare a good PR\" guide](https://softwaremill.community/t/how-to-prepare-a-good-pr-to-a-library/448). Thanks! :)\n\n## Project sponsor\n\nWe offer commercial development services. [Contact us](https://softwaremill.com) to learn more about us!\n\n## Copyright\n\nCopyright (C) 2023-2024 SoftwareMill [https://softwaremill.com](https://softwaremill.com).\n","funding_links":[],"categories":["Scala","并发编程","\u003ca name=\"Scala\"\u003e\u003c/a\u003eScala"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftwaremill%2Fox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoftwaremill%2Fox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftwaremill%2Fox/lists"}