This is the first release of Reactor 3.2, part of the Californium-RELEASE Release Train.
This major release contains a few significant new features, in addition to a heap of improvements and bug fixes.
⚠️ Update considerations and deprecations
- Compared to
3.1.x, theScannable#operatorName()method has been renamed tostepName()(#1156) Disposables.composite()now has list semantics rather than undocumented set semantics, and thus should be more performant (#1237)- The constant
Schedulers.DEFAULT_POOL_SIZEis now used internally (notably bySchedulers.[new]parallel()), but unlike before it doesn't enforce a minimum of4anymore. It can be tuned via system propertyreactor.schedulers.defaultPoolSizenow though (#1243, #1246) repeat(N)is now aligned withretry(N), as well asrepeat(N, Predicate)/retry(N, Predicate): the number indicates the amount of repetitions of the original sequence, ie0mirrors the original sequence while1mirrors the original sequence + an additional repetition of it. Negative values are rejected at assembly time. (#1252)- look out for usage of
repeat(long)in your code and decrement the passed parameter by one repeat(0)should be replaced withFlux/Mono.empty()
- look out for usage of
windowUntilandwindowWhiledon't have a final empty window at the end of the sequence (#1033)- Default behavior for
Operators.onErrorDroppedis now to both bubble and throw the errorMono.fromCompletionStagenow drops fatal exceptions rather than hanging (#1118)
- Blocking APIs (like
blockLast(),block(),iterator()) called inside a parallel or singleSchedulertrigger an exception (#1102)- This kind of blocking call are harmful as they impact limited resources, with a high risk of freezing the application
concatMapDelayErrordefault behavior is now to delay the errors until theEND(#1101)- This aligns with other *DelayError operators
StepVerifier.withVirtualTimenow use a global lock, making virtual time verifications mutually exclusive (#648)- Virtual time impacts schedulers at the application level. Parallelisation of tests could lead to unforeseen side effects due to this (initializing operators with a VTS and have the StepVerifier see and manipulate the wrong VTS)
createusesOperators.onOperatorErrorhook instead ofonErrorDropped(#1078)- (deprecation)
Scannable#operatorName()is deprecated in favor ofstepName()(#1115, #1140) - (internal) Switch to a simplified implementation for
Mono.publish(Function)(#437) - (internal) Simplify MonoProcessor internals in preparation for #1114 and further 3.2 changes
⭐ Release focus features
- Add
metrics()toFlux(#1183, #1123, 34e0d4b, #1245, #1242, #1250)- This operator does nothing if
Micrometeris not on the classpath - It exposes metrics from upstream signals visible at the operator's position in the chain
- This operator does nothing if
- Add exponential backoff retry with jitter to core:
retryWithBackoff(#1122)- This version of retry reflects what we think is the industry best practice in terms of retries.
- It is a good middle ground between the too simple
retry(n), the complexretryWhen(Function)and the more configurableRetryFunctionfromreactor-addons
- New operators for transactional reactive use cases:
usingWhen(#1220, b87ea6d, #1233, #1259)- Like
using, but the resource is provided asynchronously through aPublisher - Can have separate async "cleanup" for complete, error and cancel terminations
- Cleanups are asynchronous as well (
Function<Resource, Publisher>) and only delay the propagation of the terminal signals, NOT theonNextsignals. - Cancelled early before the resource is emitted, the
Publisher<Resource>itself is cancelled.
- Like
- New
doOnDiscard(Class, Consumer)operator (#999, #1343, #1345, #1347) - Installs a local
Contexthook that will let upstream operators in the chain clean up elements that get either filtered out of the downstream sequence or prefetched then discarded - New
onErrorContinue()mode that influences the upstream chain of operator (#629)- Supporting operators up in the chain will request more from their source in case of error, instead of terminating the sequence.
- The
Throwableis passed to a handler instead of downstream.
✨ New features and improvements
- Include sequence name in timeout()'s message (#1349)
- Replace
String.replaceAllwith a staticPatternandMatcher.replaceAllinScannable(#1315) - Added a way to strictly limit the rate of requests with
limitRate(n, 0)(#1317)- previously the
lowTideandhighTideparameter could still be changed by internal prefetching strategies - now with a
lowTideof 0, the requests will strictly adhere tohighTide
- previously the
- Blocking code detection and rejection has been improved for
toStream()andtoIterable(), and now only reject when the iteration is performed (#1313)- it would previously reject right where the
Iterablewas materialized, but what actually blocks is the act of iterating.
- it would previously reject right where the
- Improve concat error message on null Publisher (#1321)
- Calling
Mono.from(Flux.from(mono))is now immediately returning themonoinstance, as this is conceptually a no-op. (#1329)- the inverse operation (
Flux.from(Mono.from(flux))) is NOT a no-op as it transforms the originalFluxinto aMono, so it still returns a different instance.
- the inverse operation (
- Use more descriptive parameter names for buffer durations (#1331)
- The default
Schedulerpool size is now configurable via a system property (#1243) - In the case where a
QueueSubscriptionis logged vialog()during anonNext, itstoStringmethod is explicitly called (#1270)- typically this would happen when using
window()immediately followed bylog(), which is not really useful but was even less useful since it would trigger an exception
- typically this would happen when using
Tuple2..Tuple8now havemapT1..mapT8(as relevant) methods that allow to change a single part of theTuple(e4a9aee, discussed in #1058)cache(Duration)now have an overload that takes aScheduler, addedMono.cacheTTL-generator variant (#1189, #1125)Operators.liftnow has an alternative that exposes the rawPublisher:liftPublisherand supportsFuseable(#1205, #1206)- Added
zipvariants with 7 and 8 arguments (#1210 - Support 0 delay/period in
Flux.interval(#1178) - Add immutable
empty()queue Supplier toQueues, support empty and one cases inQueues.capacity()(#1161, d9d76ab) doOnEachnow supportFuseableandConditionalSubscriber(#1003)Flux.take(0)now eagerly cancels on subscription (#1158)- Lazy
Mono#fromFutureandMono#fromCompletionStageadded, withSupplierparam (#1131) - Add an
error(Supplier)variant to Flux and Mono (#1100) - Add
Scannable#steps(), which produces aStream<String>of all the stepNames both upstream and downstream (including the currentScannable) (#1115, #1140) - All operators now implement basic
Scannable(this avoids problems for users that use instanceof checks in hooks, #1136) - [kotlin] Add
Flux.splitextension to convertFlux<List<T>>toFlux<T>(#1089) - [reactor-test] Add
verifyThenAssertThat(Duration)to allow assertions and verification timeout (#1124) - [reactor-test] Allow naming of a whole StepVerifier scenario through options (#1077)
- [reactor-test] Allow to change the
LoggerFactorywith a custom implementation, provide aTestLoggerone that can be used to assert log contents (8f3a8fa) - [reactor-test] Add a cold version of the
TestPublisherthan can be set up before eg. subscribing in aStepVerifier(#1236)
🪲 Bug fixes
- Fix ClassCastException in OneQueue/ZeroQueue + Java9 build (#1326)
- When using
doOnSuccessand subscribing without an error handler, errors would be swallowed (#1337)- This now generates a
ErrorCallbackNotImplementedexception like in other cases, unless adoOnTerminateis also used - The best practice is still to always define an error handler when using
subscribe(...)
- This now generates a
- Fixed an
ArrayIndexOutOfBoundsExceptionwhen usingliftwith aParallelFluxoperator that is fuseable (can be triggered by using Sleuth, #1293) - FluxPublish should trigger an extra poll on sync fusion (#1290, #1291)
- Request fusion with
THREAD_BARRIERin concatMap* and publish (#1302) - When using a non-compliant
TestPublisher, calling.mono()would turn it into a compliant one. This has been fixed and the mono will now continue to be a bad boy (#1244) - A few
bufferTimeoutandbufferWhenissues have been corrected around cancellation and drain race conditions (#1247) Flux.last()now correctly throws aNoSuchElementExceptionon empty source even when said source is aCallable Mono(#1226)delayUntilcorrectly requestLong.MAX_VALUEand notInteger.MAX_VALUEon subscribe (#1214)Operators.lift()properly maintainGroupedFlux/ConnectableFluxinterfaces (#1204)- Request is now accounted for in `FluxOnBackpressureBufferTimeout (#1194)
- onSubscribe should be done before add in MonoCacheTime.subscribe (#1190)
- Multi-subscriber operators
Contextresolution resolves to 1st context (#1114) - Fix dangling thread when calling
WorkQueueProcessor.forceShutdown(#1142) - Let
VirtualTimeSchedulerdeferadvanceTimeif queue is empty (#783)- This avoids a situation where, due to a
subscribeOn, the operators delaying values end up reading the clock AFTER the virtual time has been moved forward bythenAwait, hanging the test.
- This avoids a situation where, due to a
- Tweak
FluxPublishdispose to clear the existing connection (#1173) - Avoid interrupting
WorkerTaskFutureif cancelled race (#1107) FluxRefCountDisconnectExceptionon cancellation race (#1088)- (internal cleanup) use passed queue in
FluxGroupBy.checkTerminated(#1094) - Only terminate ExecutorScheduler if underlying is shut down (#1080)
Mono.fromCompletionStagenow drops fatal exceptions rather than hanging (#1118)
📖 Documentation, Tests and Build
- [doc] The reference documentation has been extensively reviewed and revised for 3.2 (#1325)
- [doc] Point between Flux#create and Flux#push, show multithreading diff (3834537)
- [test] Do not fail HooksTestStaticInit test in IDE (#1322)
- [build] Add LGTM.com code quality badges (#1339)
- [doc] Fixed various javadoc marble diagram issues (#1043, #1008, #1167, #1266, #1079, #1294)
- [test] Added unit test for
SpscArrayQueue(35519ab) - Some reference documentation error fallback snippets were wrong (#1269)
- Java 9 build has been fully reactivated now that every build component is Java 9 compatible (right on time for Java 9 EoL 😁 see 2b4bf5e, 209a45f, #896, e239d65)
- Kotlin has been bumped to
1.2.51(#1274) - Document (im)mutability of Tuple2
toList()vsiterator()(#1135) - Point to reference doc operator matrix in Flux/Mono javadoc (f2bc74f)
- Warn on
doOnSubscribeusage (#1090) - various javadoc typos and minor rephrasing (#1240, #1222, 89a8e0e, #1149, #1199, 51dff9f, 4a1f691, 4e55122, #1095, 7a6a8a1, 35cb6fd, #1346)
- Various test fixes (2f74309, 0254f45, #1139, 1c27a15, 44dc73c, 8d942e1, 38f8edb, #1218)
- Add meaningful toString to FluxSink/MonoSink implementations (#1130)
🎁 Contribution process change
- Contributing Guidelines have been totally reworked and reflect the new organisation, notably in terms of labels and branching (see details below, d166557, #1225)
A notable change in the way we work with the repository and contributions that make sense for maintenance releases: as of commit 0d8e16e, there will be no more port #xxx backport commits in maintenance branches, but rather issues will be fixed first in the maintenance branch THEN a forward-merge will happen to include the fix in the master branch. See #1225.
👍 Thanks to the following contributors that also participated to this release
@alex-diez, @baptistemesta, @charlesmuchene, @genie-youn, @igoperikov, @madgnome, @MarkusJais, @nurkiewicz, @OlegDokuka, @pdudkiewicz, @smiklos, @szpak, @utwyko, @xcorail, @yamkazy, @0xflotus