From b88cd3fb992e3b33ccd317ddf5f6f28a8e13d2be Mon Sep 17 00:00:00 2001 From: adamw Date: Fri, 15 Nov 2024 11:01:05 +0100 Subject: [PATCH] Release 0.5.3 --- README.md | 4 +- generated-doc/out/basics/direct-style.md | 16 ++++-- generated-doc/out/index.md | 3 +- generated-doc/out/info/dependency.md | 4 +- generated-doc/out/integrations/kafka.md | 2 +- generated-doc/out/integrations/mdc-logback.md | 2 +- generated-doc/out/utils/rate-limiter.md | 57 +++++++++++++++++++ 7 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 generated-doc/out/utils/rate-limiter.md diff --git a/README.md b/README.md index f1d02375..6f22541e 100644 --- a/README.md +++ b/README.md @@ -23,13 +23,13 @@ the project! To test Ox, use the following dependency, using either [sbt](https://www.scala-sbt.org): ```scala -"com.softwaremill.ox" %% "core" % "0.5.2" +"com.softwaremill.ox" %% "core" % "0.5.3" ``` Or [scala-cli](https://scala-cli.virtuslab.org): ```scala -//> using dep "com.softwaremill.ox::core:0.5.2" +//> using dep "com.softwaremill.ox::core:0.5.3" ``` Documentation 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). diff --git a/generated-doc/out/basics/direct-style.md b/generated-doc/out/basics/direct-style.md index e32a4b9a..08ad1661 100644 --- a/generated-doc/out/basics/direct-style.md +++ b/generated-doc/out/basics/direct-style.md @@ -2,12 +2,18 @@ ## What is direct style? -Direct style is an approach to programming which leverages the built-in control flow constructs of the language as the -basic building blocks of effectful code. +Direct style is an approach to programming where the results of effectful computations are available directly, without +a "wrapper" type such as `Future`, `IO` or `Task`. -In direct style, I/O operations and thread synchronisations are executed as if they were blocking operations, that is -their result is available as the return value of the appropriate method call. However, specific direct style -implementations may contain special syntax that is needed to run such operations. +That way, direct-style programs can leverage the built-in control flow constructs of the language as the basic building +blocks of effectful code. + +I/O operations and thread synchronisations are executed as if they were blocking operations, even if under the hood +they are run asynchronously, using continuations (which matter for throughput & performance). + +The results of I/O operations are available "directly", as the return values of the appropriate method calls. Some +implementations may require using special syntax. In others, I/O calls are invoked as any other function or method +call, and there's no intermediate library-level runtime that is needed. ## Compiler/runtime support diff --git a/generated-doc/out/index.md b/generated-doc/out/index.md index 9627131d..7b8d1fc7 100644 --- a/generated-doc/out/index.md +++ b/generated-doc/out/index.md @@ -2,7 +2,7 @@ Safe direct-style concurrency and resiliency for Scala on the JVM. Requires JDK 21 & Scala 3. -To start using Ox, add the `com.softwaremill.ox::core:0.5.2` [dependency](info/dependency.md) to your project. +To start using Ox, add the `com.softwaremill.ox::core:0.5.3` [dependency](info/dependency.md) to your project. Then, take a look at the tour of Ox, or follow one of the topics listed in the menu to get to know Ox's API! In addition to this documentation, ScalaDocs can be browsed at [https://javadoc.io](https://www.javadoc.io/doc/com.softwaremill.ox). @@ -69,6 +69,7 @@ In addition to this documentation, ScalaDocs can be browsed at [https://javadoc. utils/oxapp utils/retries + utils/rate-limiter utils/repeat utils/scheduled utils/resources diff --git a/generated-doc/out/info/dependency.md b/generated-doc/out/info/dependency.md index 09e93615..78b4fabd 100644 --- a/generated-doc/out/info/dependency.md +++ b/generated-doc/out/info/dependency.md @@ -4,10 +4,10 @@ To use ox core in your project, add: ```scala // sbt dependency -"com.softwaremill.ox" %% "core" % "0.5.2" +"com.softwaremill.ox" %% "core" % "0.5.3" // scala-cli dependency -//> using dep com.softwaremill.ox::core:0.5.2 +//> using dep com.softwaremill.ox::core:0.5.3 ``` Ox core depends only on the Java [jox](https://github.com/softwaremill/jox) project, where channels are implemented. There are no other direct or transitive dependencies. diff --git a/generated-doc/out/integrations/kafka.md b/generated-doc/out/integrations/kafka.md index 2f6c24e9..cb0c3280 100644 --- a/generated-doc/out/integrations/kafka.md +++ b/generated-doc/out/integrations/kafka.md @@ -3,7 +3,7 @@ Dependency: ```scala -"com.softwaremill.ox" %% "kafka" % "0.5.2" +"com.softwaremill.ox" %% "kafka" % "0.5.3" ``` `Flow`s which read from a Kafka topic, mapping stages and drains which publish to Kafka topics are available through diff --git a/generated-doc/out/integrations/mdc-logback.md b/generated-doc/out/integrations/mdc-logback.md index ca912186..4c33a176 100644 --- a/generated-doc/out/integrations/mdc-logback.md +++ b/generated-doc/out/integrations/mdc-logback.md @@ -3,7 +3,7 @@ Dependency: ```scala -"com.softwaremill.ox" %% "mdc-logback" % "0.5.2" +"com.softwaremill.ox" %% "mdc-logback" % "0.5.3" ``` Ox provides support for setting inheritable MDC (mapped diagnostic context) values, when using the [Logback](https://logback.qos.ch) diff --git a/generated-doc/out/utils/rate-limiter.md b/generated-doc/out/utils/rate-limiter.md new file mode 100644 index 00000000..76e84081 --- /dev/null +++ b/generated-doc/out/utils/rate-limiter.md @@ -0,0 +1,57 @@ +# Rate limiter + +The rate limiter mechanism allows controlling the rate at which operations are executed. It ensures that at most a certain number of operations are run concurrently within a specified time frame, preventing system overload and ensuring fair resource usage. Note that the implemented limiting mechanism only takes into account the start of execution and not the whole execution of an operation. + +## API + +Basic rate limiter usage: + +```scala +import ox.supervised +import ox.resilience.* +import scala.concurrent.duration.* + +val algorithm = RateLimiterAlgorithm.FixedWindow(2, 1.second) + +supervised: + val rateLimiter = RateLimiter(algorithm) + + type T + def operation: T = ??? + + val blockedOperation: T = rateLimiter.runBlocking(operation) + val droppedOperation: Option[T] = rateLimiter.runOrDrop(operation) +``` + +`blockedOperation` will block the operation until the algorithm allows it to be executed. Therefore, the return type is the same as the operation. On the other hand, if the algorithm doesn't allow execution of more operations, `runOrDrop` will drop the operation returning `None` and wrapping the result in `Some` when the operation is successfully executed. + +A rate limiter must be created within an `Ox` [concurrency scope](../structured-concurrency/fork-join.md), as a background fork is created, to replenish the rate limiter. Once the scope ends, the rate limiter is stops as well. + +## Operation definition + +The `operation` can be provided directly using a by-name parameter, i.e. `f: => T`. + +## Configuration + +The configuration of a `RateLimiter` depends on an underlying algorithm that controls whether an operation can be executed or not. The following algorithms are available: +- `RateLimiterAlgorithm.FixedWindow(rate: Int, dur: FiniteDuration)` - where `rate` is the maximum number of operations to be executed in fixed windows of `dur` duration. +- `RateLimiterAlgorithm.SlidingWindow(rate: Int, dur: FiniteDuration)` - where `rate` is the maximum number of operations to be executed in any window of time of duration `dur`. +- `RateLimiterAlgorithm.Bucket(maximum: Int, dur: FiniteDuration)` - where `maximum` is the maximum capacity of tokens available in the token bucket algorithm and one token is added each `dur`. It can represent both the leaky bucket algorithm or the token bucket algorithm. + +### API shorthands + +You can use one of the following shorthands to define a Rate Limiter with the corresponding algorithm: + +- `RateLimiter.fixedWindow(rate: Int, dur: FiniteDuration)`, +- `RateLimiter.slidingWindow(rate: Int, dur: FiniteDuration)`, +- `RateLimiter.leakyBucket(maximum: Int, dur: FiniteDuration)`, + +See the tests in `ox.resilience.*` for more. + +## Custom rate limiter algorithms + +The `RateLimiterAlgorithm` employed by `RateLimiter` can be extended to implement new algorithms or modify existing ones. Its interface is modelled like that of a `Semaphore` although the underlying implementation could be different. For best compatibility with the existing interface of `RateLimiter`, methods `acquire` and `tryAcquire` should offer the same guaranties as Java's `Semaphores`. + +Additionally, there are two methods employed by the `GenericRateLimiter` for updating its internal state automatically: +- `def update(): Unit`: Updates the internal state of the rate limiter to reflect its current situation. Invoked in a background fork repeatedly, when a rate limiter is created. +- `def getNextUpdate: Long`: Returns the time in nanoseconds after which a new `update` needs to be called.