github reactor/reactor-core v3.4.0

latest releases: v3.8.5, v3.7.18, v3.8.4...
5 years ago

Reactor-Core 3.4.0 is part of 2020.0.0 Release Train (codename Europium).

This is the first GA release of Europium 🎉

This note focuses on 3.4.0 proper, curating changes from across all milestones.
Note that the 3.4.0 effort was started right after 3.3.5.RELEASE, so this version also contains changes from 3.3.6 to 3.3.11 (see the end of the notes for links).

⚠️ Known Issues

  • the firstWithValue new operator has an undocumented way of checking the cause of failure for individual sources, but it uses a suppressed exception rather than a cause. Please refrain from using that, as we'll switch to initCause in 3.4.1 (and properly document the behavior, setting it in stone) => #2459

⚠️ Update considerations

⚠️ 🗑️ Removals

  • Schedulers deprecated back in 3.3 have been removed (WorkQueueProcessor and TopicProcessor, #2208)
  • Previously deprecated methods and types have been removed (see #2277)

⚠️ ⌛ Deprecations

  • Schedulers.elastic() and variants are deprecated, to be removed in 3.5 (#1893)
  • FluxProcessor (as well as all concrete implementations of it) are now deprecated and will be removed in 3.5 (#2188, #2431)
    • see the main focus section below for more details
  • [api-change] MonoProcessor is made abstract and deprecated, to be removed in 3.5 (#2188, #1053 / f04bede, #2431)
    • see the main focus section below for more details
  • Flux.subscribe(Consumer<Subscription>) variant is deprecated, to be removed in 3.5 (#1825)
  • first is deprecated to be renamed to firstWithSignal (see firstWithValue in the new features below). The old deprecated method will be removed in 3.5 (#2173)
  • Context changes (#2282):
    • Operators exposing the Context at points where there is no use attempting to use write methods are deprecated and will be removed in 3.5 (#2293, 7d6c862)
      • these all receive a ContextView-based variant (see new features below)
      • deferWithContext => deferContextual with a ContextView
      • Signal.getContext() => Signal.getContextView()
    • Operators modifying the Context are renamed to be clearer. Old names are deprecated and will be removed in 3.5 (see new feature below, #2148, eed93d6)

⚠️ ♻️ Behavior Changes

  • Most operators that take a Duration and convert it to milliseconds now use nanosecond precision (#1734)
  • Operators.onErrorDropped no longer throws, but only logs the dropped exception (#1431)
  • When an onError signal reaches the last (lambda based) subscriber in a chain which doesn't have an error handler, the exception is no longer thrown but only logged (#2176)
  • Vanilla implementations of Scheduler now initiate their backing infrastructure and apply Schedulers decorator in start() rather than the constructor (#1778)
    • start() is also now implicitly called when instantiating a Scheduler via the Schedulers.Factory
    • Allows to avoid this leaking from constructor
    • ⚠️ Custom implementations should similarly initialized and optionally decorate in start()
  • EmitterProcessor with a full backpressure queue no longer blocks until data is requested, but fails fast (#2049)
  • Metrics changes
    • Change in how metric meters/tags are named in accordance with the name operator (#1928, #2302)
      • flow tag has been removed entirely
      • using the name({String}) operator will replace reactor. prefix in meter names with the user-provided {String}.
      • ⚠️ using custom tags via the tags(String...) operator, but not name(String) still creates a sparse set of tags in the application which could be rejected by some metrics backend
    • Change name of some meters that used to include (redundant) unit names (#1807)
      • reactor_requested_requested_amount => {name}_requested
      • reactor_subscribed_subscribers => {name}_subscribed
      • notice these meters also take the user-provided {name} into account from the above change
    • Differentiate empty vs valued sequences in metrics via the status tag, introducing completedEmpty value (#1803)

⚠️ ✨ Main focus: Sinks

Sinks are a new API constructed to replace the FluxProcessor and MonoProcessor APIs, which have been deprecated (#2431, #1053).

We distinguish Sinks.Many<T> (a Flux-like sink), Sinks.One<T> (a Mono-like sink) and Sinks.Empty (a Mono<Void>-like sink).

These sinks are constructed through specs under the Sinks class. They expose a two-faced API:

  • methods starting with tryEmit are atomic, never throw (#2319, #2329, #2336, #2426) and immediately return an EmitResult enum (originally named Emission) indicating various variations of success or error (#2319, #2338)
  • methods starting with emit attempt to provide an easier facade over the above, take an EmitFailureHandler allowing to fine tune some aspects of the default behavior (#2377)

By default, the instances are "serialized", detecting parallel usage and failing fast in tryEmit (#2342, #2410, #2365, 19fc1ba, #2412).
The vanilla reactor sink implementations of emit API terminate with the equivalent of an emitError when parallel usage is detected (#2365) but by using the EmitFailureHandler to drive the sink to retry, possibly with a small amount of sleeping, it should be possible to optimistically get rid of the contention.

It is also possible to get a low-overhead, low-protection instance of vanilla sinks by using the Sinks.unsafe() spec (#2418).
This doesn't detect parallel usage, so it must be used in a responsible way (in a context where the Reactive Streams contract is already externally enforced).

Sinks also expose a asFlux() view (or asMono(), as relevant) for them to be passed to downstream and subscribed, and also expose a bit of state through currentSubscriberCount() getter (#2372) and by being Scannable (at a minimum for TERMINATED and CANCELLED attributes, #2394).

Compared to existing processors, most flavors have a sink equivalent except DirectProcessor, with two close cousins under Sinks.many().multicast() (#2392, #2451):

  • directAllOrNothing will ignore tryEmitNext attempts when at least one subscriber doesn't have enough demand,
  • directBestEffort will instead push to the subset of subscribers with demand and drop from the perspective of slow subscribers.

This differs from DirectProcessor in the sense that both these sinks are kept open in such a situation, so slow subscribers that increase their request will start seeing values pushed after that (instead of being immediately terminated in DirectProcessor).

There is also a new flavor: an onBackpressureError() variant of the unicast Sink (#2347)

🐞 Bugfixes

See links to Dysprosium releases (3.3.6 to 3.3.11) at the end.

✨ New features

  • concatMap now has a variant with 0 prefetch (#2202)
  • All Scannable operators answer the new Attr.RUN_STYLE attribute with a RunStyle enum (#2058, #2123)
    • the enum allows to identify operators that run synchronously. Attribute is accessible both at Publisher and Subscriber level
    • RunStyle.SYNC guarantees the operator doesn't change threads
    • RunStyle.ASYNC indicates the operator MAY change threads
    • RunStyle.UNKNOWN (the default) indicates there's no available information (eg. due to the operator wrapping an arbitrary Publisher)
  • A Reactor-wide Micrometer MetricsRegistry other than the global one can now be configured (#2253, 64fd556)
    • Use Metrics.MicrometerConfiguration#useRegistry for that purpose
    • The above will attempt to load Micrometer classes, so Micrometer MUST be on the classpath
  • New reactive context features (#2282):
    • Context now extends a simplified ContextView API which only expose the read methods (#2279, #2293)
      • the goal is to avoid exposing a seemingly writable (copy-on-write) Context when the only meaningful operations are read operations
      • exposed in Signal#getContextView(), deferContextual operator (variant to deferWithContext) and new transformDeferredContextual operator
    • Added transformDeferredContextual operator that takes a BiFunction, allowing to access the ContextView in the transformation (#2280 then renamed in #2293)
      • Mono.subscribe(valueConsumer, errorConsumer, ...) error Consumer now gets notified of exceptions thrown by the value Consumer (#1995)
    • Renamed Context operators with clearer names (#2148, eed93d6)
      • Mono.subscriberContext() is not aliased, we now advise to use Mono.deferContextual(Mono::just) to get the exact same behavior
      • subscriberContext(Context) is replaced by contextWrite(ContextView) (notice the use of ContextView)
      • subscriberContext(Function) is replaced by contextWrite(Function)
  • Added method to snapshot factory+global schedulers (#2325, #2326, f9c7993)
    • use Schedulers.setFactoryWithSnapshot(Factory) to get a Snapshot object while replacing the Factory
    • reset the old factory by using resetFrom(Snapshot)
    • this is used by the reactor-test VirtualTimeScheduler to reset previously customized factories
  • The ParallelFlux.subscribe(array) method is now public to allow delegation in wrappers (#2328)
  • The Retry object driving #retryWhen operator can now store user-provided state in the form of a ContextView, which is exposed through RetrySignal (#2312, bd8db8a)
  • The GroupedFlux#key() method is now marked as @NonNull (#2397)
  • Added firstWithValue factory operator (#2173, 41c937f)
    • like first, it let multiple sources compete
    • except it prioritizes valued sources: empty sources are considered irrelevant
    • if no source completes with a value, a NoSuchElementException is thrown

📈 Improvements

  • Have push(emitter) delegate to push(emitter, backpressure) (#2177)
  • Lazily instantiate exception in Mono#repeatWhenEmpty (#2221)
  • log() will log context access at FINE(ST) level and now uses the more correct currentContext prefix (#2220)
  • Mono#materialize() now takes into account that the source IS a Mono, so it doesn't cancel() it when materializing its onNext (#2424, 765bfe8)
    • this could be considered a behavior change, but the previous behavior was unnecessary. cancelling the result of the materialization still propagates to the source.

📖 Documentation, Tests and Build

  • [doc] fix #2170 Make parallel runOn methods doc consistent about work stealing
  • [doc] Document Android 21 desugaring options (#2232)
  • [build] #2237 remove most compilation warnings
  • [doc] fix #2136 Turn discard/errorMode javadoc tags into plain paragraphs
  • [build] fix #2400 use a different name for the jcstress jar
  • [build] Remove compilation warnings related to jsr305 (85da74b)

👍 Thanks to the following contributors that also participated to this release

@AayushyaVajpayee, @camsteffen, @cnabro, @hamidshahid, @Inego, @jonenst, @josemalonsom, @OlegDokuka, @robotmrv, @seants, @smaldini, @steppedreckoner, @yschimke

Links to Dysprosium release notes during 3.4.0 development effort

All changes from these releases have been forward-merged into 3.4.0:

Don't miss a new reactor-core release

NewReleases is sending notifications on new releases.