diff --git a/README.md b/README.md index dd92cea6..5eda95f0 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.3.2" +"com.softwaremill.ox" %% "core" % "0.3.3" ``` Or [scala-cli](https://scala-cli.virtuslab.org): ```scala -//> using dep "com.softwaremill.ox::core:0.3.2" +//> using dep "com.softwaremill.ox::core:0.3.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/adr/0001-error-propagation-in-channels.md b/generated-doc/out/adr/0001-error-propagation-in-channels.md index 9ddc6e18..15651243 100644 --- a/generated-doc/out/adr/0001-error-propagation-in-channels.md +++ b/generated-doc/out/adr/0001-error-propagation-in-channels.md @@ -24,7 +24,7 @@ If there are multiple forks running in parallel, there are two possible scenario cancelling any forks that are operating in the background. Any unused channels can then be garbage-collected. 2. If you choose not to re-throw, the forks running in parallel would be allowed to complete normally (unless the containing scope is finished for another reason). -Internally, for the built-in `Source` operators, we took the latter approach, i.e. we chose not to re-throw and let the parrallel forks complete normally. +Internally, for the built-in `Source` operators, we took the latter approach, i.e. we chose not to re-throw and let the parallel forks complete normally. However, we keep in mind that they might not be able to send to downstream channel anymore - since the downstream might already be closed by the failing fork. ### Example @@ -49,7 +49,7 @@ def mapParUnordered[U](parallelism: Int)(f: T => U)(using Ox, StageCapacity): So try c.send(f(t)) // (4) s.release() - catch case t: Throwable => c.error(t) // (5) + catch case e: Exception => c.error(t) // (5) } true } diff --git a/generated-doc/out/adr/0003-why-source-operators-do-not-throw.md b/generated-doc/out/adr/0003-why-source-operators-do-not-throw.md index d2f0b8bb..57f0bc6b 100644 --- a/generated-doc/out/adr/0003-why-source-operators-do-not-throw.md +++ b/generated-doc/out/adr/0003-why-source-operators-do-not-throw.md @@ -8,9 +8,6 @@ Revisiting ADR #1, what should happen when an error is encountered when processi ## Decision -In addition to what's mentioned in ADR #1, operators don't throw, but propagate, because: - -* we might be in a non-supervised scope, so the errors would disappear silently (as the intermediate forks aren't visible to the end user, and are not supervised in this scenario) -* we want to allow throw-free coding style. When errors are propagated, on error every daemon operator thread shuts down, and we end the scope gracefully. +In addition to what's mentioned in ADR #1, operators don't throw, but propagate, because we want to allow throw-free coding style. When errors are propagated, on error every daemon operator thread shuts down, and we end the scope gracefully. Additionally, we assume that data only flows downstream - and this includes errors. diff --git a/generated-doc/out/basics/start-here.md b/generated-doc/out/basics/start-here.md index 4b75e577..71599744 100644 --- a/generated-doc/out/basics/start-here.md +++ b/generated-doc/out/basics/start-here.md @@ -4,10 +4,10 @@ ```scala // sbt dependency -"com.softwaremill.ox" %% "core" % "0.3.2" +"com.softwaremill.ox" %% "core" % "0.3.3" // scala-cli dependency -//> using dep com.softwaremill.ox::core:0.3.2 +//> using dep com.softwaremill.ox::core:0.3.3 ``` ## Scope of the Ox project diff --git a/generated-doc/out/index.md b/generated-doc/out/index.md index d6c3057d..8a55eb53 100644 --- a/generated-doc/out/index.md +++ b/generated-doc/out/index.md @@ -74,9 +74,10 @@ In addition to this documentation, ScalaDocs can be browsed at [https://javadoc. .. toctree:: :maxdepth: 2 - :caption: Kafka integration + :caption: Integrations kafka + mdc-logback .. toctree:: :maxdepth: 2 diff --git a/generated-doc/out/io.md b/generated-doc/out/io.md index a15588b4..f034d6d5 100644 --- a/generated-doc/out/io.md +++ b/generated-doc/out/io.md @@ -68,13 +68,13 @@ To use the plugin, add the following settings to your sbt configuration: ```scala autoCompilerPlugins := true -addCompilerPlugin("com.softwaremill.ox" %% "plugin" % "0.3.2") +addCompilerPlugin("com.softwaremill.ox" %% "plugin" % "0.3.3") ``` For scala-cli: ```scala -//> using plugin com.softwaremill.ox:::plugin:0.3.2 +//> using plugin com.softwaremill.ox:::plugin:0.3.3 ``` With the plugin enabled, the following code won't compile: diff --git a/generated-doc/out/kafka.md b/generated-doc/out/kafka.md index c3de86fa..c867b911 100644 --- a/generated-doc/out/kafka.md +++ b/generated-doc/out/kafka.md @@ -3,7 +3,7 @@ Dependency: ```scala -"com.softwaremill.ox" %% "kafka" % "0.3.2" +"com.softwaremill.ox" %% "kafka" % "0.3.3" ``` `Source`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/mdc-logback.md b/generated-doc/out/mdc-logback.md new file mode 100644 index 00000000..a69a4dae --- /dev/null +++ b/generated-doc/out/mdc-logback.md @@ -0,0 +1,46 @@ +# Inheritable MDC using Logback + +Ox provides support for setting inheritable MDC (mapped diagnostic context) values, when using the [Logback](https://logback.qos.ch) +logging library. Normally, value set using `MDC.put` aren't inherited across (virtual) threads, which includes forks +created in concurrency contexts. + +Inheritable values are especially useful e.g. when setting a correlation id in an HTTP request interceptor, or at any +entrypoint to the application. Such correlation id values can be then added automatically to each log message, provided +the appropriate log encoder pattern is used. + +To enable using inheritable MDC values, the application's code should call `InheritableMDC.init` as soon as possible. +The best place would be the application's entrypoint (the `main` method). + +Once this is done, inheritable MDC values can be set in a scoped & structured manner using `InheritableMDC.supervisedWhere` +and variants. + +As inheritable MDC values use a [`ForkLocal`](structured-concurrency/fork-local.md) under the hood, their usage +restrictions apply: outer concurrency scopes should not be used to create forks within the scopes. Only newly created +scopes, or the provided scope can be used to create forks. That's why `supervisedError`, `unsupervisedError` and +`supervisedErrorWhere` methods are provided. + +"Normal" MDC usage is not affected. That is, values set using `MDC.put` are not inherited, and are only available in +the thread where they are set. + +For example: + +```scala +import org.slf4j.MDC + +import ox.fork +import ox.logback.InheritableMDC + +InheritableMDC.supervisedWhere("a" -> "1", "b" -> "2") { + MDC.put("c", "3") // not inherited + + fork { + MDC.get("a") // "1" + MDC.get("b") // "2" + MDC.get("c") // null + }.join() + + MDC.get("a") // "1" + MDC.get("b") // "2" + MDC.get("c") // "3" +} +```