Contributors: your thoughts on restoring the sync API for 7.x? #1738
Replies: 13 comments 13 replies
-
I am no longer a regular contributor to this client but I do maintain and contribute to a good dozen of RabbitMQ client libraries, and see how they are used and abused virtually every day. So I guess my opinion can be approximated to that of a contributor, or at least a former contributor with a lot of relevant experience elsewhere. Most clients only support one API, be it sync or async. Mind you, the In those languages, usually it's either "all async" or "all sync". PythonSome examples in Python:
So async-only libraries for Python are the norm, even if Pika, which is used in RabbitMQ tutorials, is an exception or not an "async-only" client. JavaScript, TypeScriptMoving on to JavaScript:
So in the JavaScript world we see the same situation: older clients offer two different APIs, RustIn Rust, mixing async and sync code is fairly complicated. Quite a few libraries prefer an async interface, while providing some helpers for when there are reasons to not use JavaIn Java, there is a couple of client libraries but the absolutely dominant one is the one we have. It offers a sync-ish API and two options for I/O: regular synchronous one and NIO (async I/O). NIO has been a hotly requested feature for years and a non-trivial percentage of direct users have adopted it, as far as I can tell. Hop, the HTTP API Java client, supports both a sync and async APIs but it is a library much smaller in scope and changes only when something is added to the HTTP API. In other words, it is easy to maintain the two versions because it does not take a lot of maintenance in general, and that is not the case for the .NET AMQP 0-9-1 client. .NET Stream Client.NET client for the RabbitMQ Stream Protocol only offers an When Did Async API Discussions Start?About eight years ago, with #307 being the first specific API change, a new The biggest discussion of that era was #83, Over time, however, the requests started being heavily skewed towards "when will the What I am getting from this issue/discussion archeology is that the expectations of this client have gradually moved to an And most discussions after Will RabbitMQ .NET Client 6.x Be Compatible with RabbitMQ 4.x?Let's have a look at whether using .NET client 6.x with its sync API would be a feasible alternatives for those who won't be able to make the switch in 2024-2025. RabbitMQ's implementation of AMQP 0-9-1 changes rarely, and usually with additions of small protocol extensions for specific problems, such as RabbitMQ .NET client 2.0 can still connect to RabbitMQ 4.x, and .NET client 7.x can still connect to RabbitMQ 2.0+ all the way to 4.0. In other words, there's a chance that .NET client 6.x users will be able to adopt future RabbitMQ 4.x and, say, 5.x releases with no or very few changes, all while using the same good ole sync API. Now, whether there will be any support offered for 6.x down the road, I don't know, but the client So What is Your Vote?I don't have a strong opinion. If the sync client will prove to be difficult to maintain alongside the async one, I vote against restoring the sync API. If the sync client can be maintained with a small amount of effort and without holding back the new async API, keeping it in Based on earlier discussions, this is a big if. |
Beta Was this translation helpful? Give feedback.
-
I have also asked a couple of RabbitMQ client library contributors to take a look. I cannot know if they'd like to comment on a .NET client specifically, let's see. |
Beta Was this translation helpful? Give feedback.
-
Now there is a speculation on a certain .NET community member social media account that claims that some of the contributors mentioned above have "pressured" our team to decide one way or another. I've been a RabbitMQ contributor since 2010 one way or another, and a contributor this client since 2013 (not so much recently but still). During this time period, some of the folks above have been contributing regularly since at least 2015. They have developed trust and good will with this team, and it's the most natural thing in an open source project that those who contribute regularly get to influence the direction of the project, and those who do not even participate in discussions have no influence. So with that out of the way, let's see what are the contributing folk willing to do about the 6.x API. It can be re-introduced, or 6.x can be maintained for another year or so (including shipping new minors if necessary), or a new façade library can be built on top of the 7.x API as a separate library. Step one is deciding if there's any interest in maintaining the 6.x API of sorts for the longer term, or the 6.x series. Speaking of which, the 6.x series will enjoy a period of maintenance in any case, and can be used with RabbitMQ 4.0, future 4.1, and most likely a reasonable number of releases down the road simply because protocol-level changes are incredibly rare. I recall two limited ones in the ≈ 18 year old history of this library. |
Beta Was this translation helpful? Give feedback.
-
There are some strong opinions/comments in there, so I will allow myself some. A single synchronous blocking operation is usually more performant than an asynchronous one. Asynchronous operations are about availability and scalability and not single operation performance. I'm simply not having a discussion about .NET/C# with someone that writes code like But this is not about a single comment and about all users. I haven't yet delved into the changes needed to adapt my code to version 7, so I don't have first hand experience. But, since 6.x is supported and can be used, and synchronous APIs have to mostly be reimplemented, I'd measure first before drawing a conclusion. What are the downloads of 7.x versus 6.x? |
Beta Was this translation helpful? Give feedback.
-
If users wish to continue using the old API, they are more than welcome to use and contribute to the If we get enough feedback, especially from businesses with commercial RabbitMQ licenses, that indicates this topic should be re-visited, we can do so for version 8. |
Beta Was this translation helpful? Give feedback.
-
Thanks for inviting me to this conversation. I’d like to emphasize that these are my opinions and not those of my employer. For me, contributing to the RabbitMQ client has always been more of a hobby or side project. I enjoy the community and the opportunity to tackle real-world challenges I can help solve. Of course, this is only possible because I have the context from the problem domain I interact with during my day job, as well as the privilege of a job that pays the bills—allowing me the luxury of treating evening coding as an enjoyable hobby. Taking a step back and reviewing the previous discussion linked in this thread, I wonder if we may have ventured too quickly into somewhat emotional territory. I can’t speak for everyone involved, but knowing both Ian and Michael for a long time (albeit mostly asynchronously—pun intended), I believe all parties are genuinely trying to find the best way forward. It seems that some aspects of the conversation may have gotten “lost in translation.” For example, from various discussions with @iancooper, I’ve learned that he genuinely embodies the spirit of open source. He strives to collaborate and support both his community and the broader one here. I’m fairly certain that his comments in the other thread were made with good intentions. Given Ian’s extensive experience with various messaging solutions across platforms, I think it would be valuable to give him the benefit of the doubt and re-engage him in this conversation. We all have the opportunity to learn from one another here. I’ll follow up with some subject-specific input a bit later. I look forward to continuing this discussion with all of you. |
Beta Was this translation helpful? Give feedback.
-
Now that I’ve made the other comment, here are my thoughts on the discussion and some of the points raised throughout the conversation, which are spread across multiple issues and discussions.
This is an absolutely correct observation from @iancooper. Using
The result is that two threads are used instead of one to complete synchronous operations. This often leads to thread pool starvation, potentially causing service outages.
This is also true. Introducing an async API deep in the call stack requires making the entire call chain asynchronous up to the entry point. These restrictions may be due to factors beyond the owning team's control. For widely used methods, the "virality" of async can cause ripple effects throughout the codebase, complicating containment of changes. While guidelines and resources (including my talk—shameless plug!) can help address these challenges, valid business or monetary reasons might justify not adopting async. My question is: when such valid decisions are made, how much interest remains in switching to a modern library version beyond addressing security vulnerabilities?
This is a controversial topic, with arguments on both sides. Putting aside memory considerations for a moment, the Orleans: Distributed Virtual Actors for Programmability and Scalability paper was enlightening for me a few years ago. The paper discusses how Orleans uses asynchronous I/O and cooperative multitasking to mask latency in distributed actor calls (Section 5.1). Switching RPC calls to asynchronous in .NET achieves similar benefits, as shown in Orleans benchmarks. With synchronous RPC, each call blocks a thread, tying up resources during I/O-bound operations like network calls or database queries. In contrast, asynchronous RPC frees threads to handle other tasks while waiting, improving overall throughput. Section 3.4 of the Orleans paper highlights how asynchronous operations prevent application code from holding a thread during I/O, maximizing throughput in distributed systems. Similarly, .NET’s The benchmarks in Section 5.1 demonstrate how asynchronous I/O and cooperative multitasking mask latency in actor calls. These principles directly apply to asynchronous RPC in .NET, leading to better resource utilization and higher throughput. However, as David Kean noted in a linked discussion, synchronous I/O can sometimes be better—particularly when the underlying I/O system "fakes" I/O completion ports by offloading continuations to the worker thread pool. Yet, this seems like a small corner case taken out of context. See also: Synchronous I/O Anti-Pattern. Let’s also not forget that the underlying thread pool and async state machines are continuously improved, making some edge cases less relevant over time.
This is an interesting argument. It suggests that SDK authors shouldn’t make decisions on behalf of users, such as dropping support for older frameworks. However, just as users may have valid reasons to stay on an older platform, SDK maintainers can have valid reasons to cease supporting certain parts of an SDK when the cost-benefit ratio no longer makes sense. This is perhaps the crux of the discussion: some in the community favor progress, sometimes at the expense of having to let go something else, while others advocate for maintaining "legacy" support. The community favoring progress might dominate the conversation here, creating an echo chamber that overlooks alternative contexts. Discussions like this are valuable, provided the RabbitMQ maintainer team’s perspective is also considered. From my understanding, the .NET client has one official maintainer, with the rest being community-driven. This dynamic may further contribute to the echo chamber effect I’ve mentioned before. In my opinion, properly supporting both API styles ("colors") means duplicating effort in some areas, such as maintaining and fixing bugs in two paths because two "cores" are required. This increases the SDK’s maintenance overhead and diverts resources from potential improvements. Ultimately, it’s about making trade-offs based on available resources. There are also "less puristic" but "convenient" approaches, such as providing a sync-over-async wrapper like RavenDB’s These wrappers simplify usage but may still hide thread pool starvation issues, requiring users to tweak thread pool limits to avoid problems. That being said, I'm not against re-introducing the synchronous variants when all those things have been considered |
Beta Was this translation helpful? Give feedback.
-
Michael asked me to share my thoughts on this topic. I have contributed here and there to this library, but I have far less knowledge of the codebase than many here. I'm generally on the side that favours progress, over maintaining "legacy" for decades. This doesn't mean maintainers get a free card to make breaking changes all around. When I was asked about removing the sync part of this library, I was in favour, and I still think it was a good decision, because Luke found many challenges to keep both APIs available, and we had many signals, from trusted sources, to move the API to async (as Michael pointed out regarding trusted contributors). My opinion is that "legacy" should not hinder progress and natural evolution. A company or a person can have valid reasons to not modernise some of their code. It is their decision to stay behind, with the consequences that comes with such decision.
I don't agree to this opinion. When SDK authors give you a toolkit, you are expected to use the toolkit in a certain way, with some restrictions, assumptions and opinions that come with the SDK. You can argue about the restrictions and opinions, but you can't have an "opinion-free" SDK. This effectively means that an SDK will make some choices for you, with the intent of helping you solve a problem. If you don't like those choices, or opinions, then simply don't use the SDK. I vote for keeping |
Beta Was this translation helpful? Give feedback.
-
Correct. It's not that (at least most) maintainers "despise" the 6.x API. We simply don't want to stretch ourselves too thin maintaining both. But as long as there are 6.x users who are willing to meaningfully contribute (to this generally very mature library), 6.x can be kept afloat (or even meaningfully improved within the limits of minor and patch releases). |
Beta Was this translation helpful? Give feedback.
-
I vote for keeping the sync API going forward. I do not think that using async is the right way in all cases however if our API is going to force users to use async it means that they have to, literally, "work around". Typically creating a wrapper that converts the async-api to a sync one. Of course, as owners of the api, we can decide what is best for the users while keeping the code maintainable. But here, I am not so sure it is justifiable to drop the sync-api. |
Beta Was this translation helpful? Give feedback.
-
Thanks for allowing me to comment. Can I first take this opportunity to apologize to you all for any upset my words caused you. I will try to choose my words more carefully. I would like to re-iterate my comment in the issue that I am grateful for all the hard work on V7, to produce an async version. It will be enormously helpful. I have nothing but respect for the work of the people here, some of whom I know, and I am mortified that my comments were ill-thought out, and upset you. |
Beta Was this translation helpful? Give feedback.
-
Moving on from this comment, I recognize the comments by @lukebakken about the constraints he is under as the only developer, and therefore his need to control the scope of the work. Pragmatically, that does mean the solution is for the community to self-service the sync API provided by V6 for now. Thanks for listening to my request thoughtfully in this thread though. I can certainly try to give some of my free time to that end. |
Beta Was this translation helpful? Give feedback.
-
I did want to clarify one point about my use of the word SDK and why it is that I perceive that there a difference between an SDK and a framework. With a framework, you are offering reusable code to solve a common problem. It may well have strong opinions. That is great because it is likely that we will have a lot of frameworks, representing different developers opinions, and you get to choose ones that suit you. In the dotnet space, if you don't like my opinions on Brighter, you can instead go and choose the opinions of Mass Transit, Wolverine or NServiceBus. That is good, and a healthy ecosystem should have lots of fine opinions for you to choose from. There is an easy escape route. You can sidestep frameworks you don't like altogether and have no framework if you desire; which is another kind of escape route and the problem is in many parts greater effort over more difficult. For me, an SDK does more than this, it abstracts a particular protocol for your chosen development language. If I can't use your SDK, for whatever reason, my escape route is to use the protocol directly. Now, if my SDK abstracts an HTTP+JSON API, a lot of developers will have the skills to escape the SDK, and write their own. Perhaps they can even share it. But once I get into a protocol like amqp 0-9-1 the number of developers who can escape the official SDK and write their own is going to be far fewer. The contributors to this repo might be a lot of the folks who can do that for the dotnet community. And that means there are possibly no escape routes for folks. |
Beta Was this translation helpful? Give feedback.
-
Background
This is a question specifically for those who regularly contribute to this client or at least participate in discussions (which is also a form of contribution):
@lukebakken @stebet @bording @danielmarbach @bollhals @paulomorgado @kjnilsson @Gsantomaggio
It is a follow-up to #1737 where some very strong opinions were expressed by a person who has never contributed to this client. The author of that issue won't participate in this discussion due to interaction limits for 30 days, as I don't think we need to hear how "us maintainers are all dummies, this non-contributor knows better know what Joe and Jill the regular users need" one more time 😮💨
The Decision We are Seeking to Make
Should we revert #1472 for
7.x
specifically.I am not even trying to ask about a possibility to forward port such an API to 8.x and future versions. If we cannot agree to support a sync API even in
7.x
, the idea of longer term support is DOA.Earlier Considerations
This is not the first time this topic was brought up amongst the maintainers. Some earlier discussions:
Beta Was this translation helpful? Give feedback.
All reactions