{"id":421019,"date":"2024-06-30T03:49:56","date_gmt":"2024-06-30T03:49:56","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=421019"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=421019","title":{"rendered":"<span>Spring Reactor Mono::block deadlock<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/511\/6e6\/2fe\/5116e62fe07ec291f3ec2115d7731e4c.png\" alt=\"And where is the deadlock here?\" title=\"And where is the deadlock here?\" width=\"528\" height=\"309\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/511\/6e6\/2fe\/5116e62fe07ec291f3ec2115d7731e4c.png\"\/><\/p>\n<div><figcaption>And where is the deadlock here?<\/figcaption><\/div>\n<\/figure>\n<p>Faced with the situation when calling <strong>Mono::block leads to deadlock<\/strong> &#8212; in debug I can just see how it stands on Unsafe::park and no more movement at all.<\/p>\n<hr\/>\n<p>Actually this is the code example with described problem.<\/p>\n<pre><code class=\"java\">Flux&lt;PojoClass> pojoClassFlux = Flux.fromIterable(pojoClassSet);  pojoClassFlux         .groupBy(PojoClass::getInteger)         .map(pojoClassIntegerGroupedFlux -> pojoClassIntegerGroupedFlux                 .map(pojoClass -> {                     \/\/some mapping                 })                 .reduce(new PojoClassIntegerGroup(), (currentPojoClassIntegerGroup, newSourceFilterToColumn) -> {                     \/\/some reduce function                 })         )\/\/ &lt;-- Flux&lt;Mono&lt;PojoClassIntegerGroup>>         .reduce(new PojoClassIntegerAllGroup(), (currentPojoClassIntegerAllGroup, newPojoClassIntegerGroupMono) -> {                     PojoClassIntegerGroup newPojoClassIntegerGroup = newPojoClassIntegerGroupMono                             .block();\/\/ &lt;-- here is the DEADLOCK!                     \/\/ do something with newPojoClassIntegerGroup for reduce                 }         )         .subscribe(\/\/do something,                 throwable -> {                     \/\/throw the problem                 },                 () -> log.info(\"SUCCESS\")         ); <\/code><\/pre>\n<p>So, at the point of <strong>newPojoClassIntegerGroupMono.block()<\/strong> of my example, I got stack of JVM awaiting for something at <strong>Unsafe::park<\/strong> method.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b2c\/5b9\/b0a\/b2c5b9b0a1d4db808838c959880c99fd.png\" alt=\"Continuous awaiting at Unsafe::park method.\" title=\"Continuous awaiting at Unsafe::park method.\" width=\"757\" height=\"509\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b2c\/5b9\/b0a\/b2c5b9b0a1d4db808838c959880c99fd.png\"\/><\/p>\n<div><figcaption>Continuous awaiting at <strong>Unsafe::park<\/strong> method.<\/figcaption><\/div>\n<\/figure>\n<p>And it happens nothing after awaiting for some time &#8212; the debug point not moving at all. For current example it was used next version of reactor-core dependency in pom.xml:<\/p>\n<pre><code class=\"java\">&lt;dependency>     &lt;groupId>io.projectreactor&lt;\/groupId>     &lt;artifactId>reactor-core&lt;\/artifactId>     &lt;version>3.3.10.RELEASE&lt;\/version> &lt;\/dependency><\/code><\/pre>\n<p>Here you can find the link to registered issue at GitHub for reactor-core:<\/p>\n<blockquote>\n<p><a href=\"https:\/\/github.com\/reactor\/reactor-core\/issues\/1651\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/reactor\/reactor-core\/issues\/1651<\/a><\/p>\n<\/blockquote>\n<blockquote>\n<p>But how can we solve our case now?<\/p>\n<\/blockquote>\n<p>We can use <strong>Flux::flatMap<\/strong> instead of <strong>Flux::map<\/strong> function after groupBy. And then our code example become like below &#8212; it works!<\/p>\n<pre><code class=\"java\">pojoClassFlux         .groupBy(PojoClass::getInteger)         .flatMap(pojoClassIntegerGroupedFlux -> pojoClassIntegerGroupedFlux \/\/ &lt;-- flatMap here                 .map(pojoClass -> {                     \/\/some mapping                 })                 .reduce(new PojoClassIntegerGroup(), (currentPojoClassIntegerGroup, newSourceFilterToColumn) -> {                     \/\/some reduce function                 })         )\/\/ &lt;-- Flux&lt;PojoClassIntegerGroup> here after flatMap         .reduce(new PojoClassIntegerAllGroup(), (currentPojoClassIntegerAllGroup, newPojoClassIntegerGroup) -> {                     \/\/do something with the newPojoClassIntegerGroup for reduce -- no need for Mono::block!                 }         )         .subscribe(\/\/do something with final PojoClassIntegerAllGroup,                 throwable -> {                     \/\/throw the problem                 },                 () -> log.info(\"SUCCESS\")         ); <\/code><\/pre>\n<p>Using <strong>Flux::flatMap<\/strong> here, we will remove passing of unnecessary Mono inside of Flux at final reduce step &#8212; it will be just Flux&lt;PojoClassIntegerGroup> &#8212; what we need!<\/p>\n<p>At least if there is a need to work with the result &#8212; it can be used <strong>Mono::subscribe<\/strong> to set some <strong>AtomicReference field<\/strong> with the result of Mono, instead of Mono::block directly. See example below:<\/p>\n<pre><code class=\"java\">AtomicReference&lt;MyBestPojoClass> myBestPojoClassHolder = new AtomicReference&lt;>(); pojoClassMono.subscribe(myBestPojoClassHolder::set);<\/code><\/pre>\n<hr\/>\n<p>It is better not to call blocking operation in general and Mono::block particularly at all when working with Spring Reactor. This example demonstrates how it could lead to deadlock. In this case you can see how Flux::flatMap removes Mono inside of Flux&lt;Mono&lt;PojoClassIntegerGroup>> &#8212; and we can work directly with returned type without calling blocking method. If very needed to extract the result of Mono then try <strong>Mono::subscribe <\/strong>to set the field as described above in this article. If you have your own recipe of how to avoid call to block in some cases with Reactor &#8212; please feel free to write comments here.<\/p>\n<p>If you have what to say about the topic and want to give negative rating &#8212; please feel free to write your comments to understand your opinion. Otherwise it is not serious and it is not clear why you vote negatively.<\/p>\n<p>And of course If you like this article, please vote UP &#8212; this will support me to write more such posts with real code examples!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/741464\/\"> https:\/\/habr.com\/ru\/articles\/741464\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\">\n<div><figcaption>And where is the deadlock here?<\/figcaption><\/div>\n<\/figure>\n<p>Faced with the situation when calling <strong>Mono::block leads to deadlock<\/strong> &#8212; in debug I can just see how it stands on Unsafe::park and no more movement at all.<\/p>\n<hr\/>\n<p>Actually this is the code example with described problem.<\/p>\n<pre><code class=\"java\">Flux&lt;PojoClass> pojoClassFlux = Flux.fromIterable(pojoClassSet);  pojoClassFlux         .groupBy(PojoClass::getInteger)         .map(pojoClassIntegerGroupedFlux -> pojoClassIntegerGroupedFlux                 .map(pojoClass -> {                     \/\/some mapping                 })                 .reduce(new PojoClassIntegerGroup(), (currentPojoClassIntegerGroup, newSourceFilterToColumn) -> {                     \/\/some reduce function                 })         )\/\/ &lt;-- Flux&lt;Mono&lt;PojoClassIntegerGroup>>         .reduce(new PojoClassIntegerAllGroup(), (currentPojoClassIntegerAllGroup, newPojoClassIntegerGroupMono) -> {                     PojoClassIntegerGroup newPojoClassIntegerGroup = newPojoClassIntegerGroupMono                             .block();\/\/ &lt;-- here is the DEADLOCK!                     \/\/ do something with newPojoClassIntegerGroup for reduce                 }         )         .subscribe(\/\/do something,                 throwable -> {                     \/\/throw the problem                 },                 () -> log.info(\"SUCCESS\")         ); <\/code><\/pre>\n<p>So, at the point of <strong>newPojoClassIntegerGroupMono.block()<\/strong> of my example, I got stack of JVM awaiting for something at <strong>Unsafe::park<\/strong> method.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Continuous awaiting at <strong>Unsafe::park<\/strong> method.<\/figcaption><\/div>\n<\/figure>\n<p>And it happens nothing after awaiting for some time &#8212; the debug point not moving at all. For current example it was used next version of reactor-core dependency in pom.xml:<\/p>\n<pre><code class=\"java\">&lt;dependency>     &lt;groupId>io.projectreactor&lt;\/groupId>     &lt;artifactId>reactor-core&lt;\/artifactId>     &lt;version>3.3.10.RELEASE&lt;\/version> &lt;\/dependency><\/code><\/pre>\n<p>Here you can find the link to registered issue at GitHub for reactor-core:<\/p>\n<blockquote>\n<p><a href=\"https:\/\/github.com\/reactor\/reactor-core\/issues\/1651\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/reactor\/reactor-core\/issues\/1651<\/a><\/p>\n<\/blockquote>\n<blockquote>\n<p>But how can we solve our case now?<\/p>\n<\/blockquote>\n<p>We can use <strong>Flux::flatMap<\/strong> instead of <strong>Flux::map<\/strong> function after groupBy. And then our code example become like below &#8212; it works!<\/p>\n<pre><code class=\"java\">pojoClassFlux         .groupBy(PojoClass::getInteger)         .flatMap(pojoClassIntegerGroupedFlux -> pojoClassIntegerGroupedFlux \/\/ &lt;-- flatMap here                 .map(pojoClass -> {                     \/\/some mapping                 })                 .reduce(new PojoClassIntegerGroup(), (currentPojoClassIntegerGroup, newSourceFilterToColumn) -> {                     \/\/some reduce function                 })         )\/\/ &lt;-- Flux&lt;PojoClassIntegerGroup> here after flatMap         .reduce(new PojoClassIntegerAllGroup(), (currentPojoClassIntegerAllGroup, newPojoClassIntegerGroup) -> {                     \/\/do something with the newPojoClassIntegerGroup for reduce -- no need for Mono::block!                 }         )         .subscribe(\/\/do something with final PojoClassIntegerAllGroup,                 throwable -> {                     \/\/throw the problem                 },                 () -> log.info(\"SUCCESS\")         ); <\/code><\/pre>\n<p>Using <strong>Flux::flatMap<\/strong> here, we will remove passing of unnecessary Mono inside of Flux at final reduce step &#8212; it will be just Flux&lt;PojoClassIntegerGroup> &#8212; what we need!<\/p>\n<p>At least if there is a need to work with the result &#8212; it can be used <strong>Mono::subscribe<\/strong> to set some <strong>AtomicReference field<\/strong> with the result of Mono, instead of Mono::block directly. See example below:<\/p>\n<pre><code class=\"java\">AtomicReference&lt;MyBestPojoClass> myBestPojoClassHolder = new AtomicReference&lt;>(); pojoClassMono.subscribe(myBestPojoClassHolder::set);<\/code><\/pre>\n<hr\/>\n<p>It is better not to call blocking operation in general and Mono::block particularly at all when working with Spring Reactor. This example demonstrates how it could lead to deadlock. In this case you can see how Flux::flatMap removes Mono inside of Flux&lt;Mono&lt;PojoClassIntegerGroup>> &#8212; and we can work directly with returned type without calling blocking method. If very needed to extract the result of Mono then try <strong>Mono::subscribe <\/strong>to set the field as described above in this article. If you have your own recipe of how to avoid call to block in some cases with Reactor &#8212; please feel free to write comments here.<\/p>\n<p>If you have what to say about the topic and want to give negative rating &#8212; please feel free to write your comments to understand your opinion. Otherwise it is not serious and it is not clear why you vote negatively.<\/p>\n<p>And of course If you like this article, please vote UP &#8212; this will support me to write more such posts with real code examples!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/741464\/\"> https:\/\/habr.com\/ru\/articles\/741464\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-421019","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/421019","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=421019"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/421019\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=421019"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=421019"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=421019"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}