<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hailay Gebreslasie Gebremeskel</title>
    <description>The latest articles on DEV Community by Hailay Gebreslasie Gebremeskel (@hailay).</description>
    <link>https://dev.to/hailay</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3892585%2F9777b411-f2fe-43cc-9103-ef9ba18b0897.jpg</url>
      <title>DEV Community: Hailay Gebreslasie Gebremeskel</title>
      <link>https://dev.to/hailay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hailay"/>
    <language>en</language>
    <item>
      <title>Mind Your Business (Not Your Message Broker)</title>
      <dc:creator>Hailay Gebreslasie Gebremeskel</dc:creator>
      <pubDate>Mon, 12 Oct 2026 10:25:41 +0000</pubDate>
      <link>https://dev.to/hailay/mind-your-business-not-your-message-broker-2fn7</link>
      <guid>https://dev.to/hailay/mind-your-business-not-your-message-broker-2fn7</guid>
      <description>&lt;p&gt;You built an application. It works. Messages are flowing between services, and everything looks fine.&lt;/p&gt;

&lt;p&gt;Then one day, a queue starts growing unexpectedly. Memory usage increases. A connection drops. Or you need to upgrade your message broker without interrupting the application.&lt;/p&gt;

&lt;p&gt;Suddenly, instead of working on the feature you planned to build, you're investigating infrastructure.&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;p&gt;Message brokers are an important part of many applications. They help services communicate asynchronously, distribute work, and handle workloads without requiring every component to be available at the same time.&lt;/p&gt;

&lt;p&gt;But there's something we don't always talk about when choosing a message broker: &lt;strong&gt;who is going to operate it?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Open source gives you freedom
&lt;/h2&gt;

&lt;p&gt;Take &lt;a href="https://lavinmq.com" rel="noopener noreferrer"&gt;LavinMQ&lt;/a&gt;, for example.&lt;/p&gt;

&lt;p&gt;LavinMQ is an open-source message broker that supports AMQP and MQTT. You can download it, install it on your own infrastructure, and use it without paying a software license fee.&lt;/p&gt;

&lt;p&gt;Similar to RabbitMQ, you can self-host it and decide how it fits into your application architecture.&lt;/p&gt;

&lt;p&gt;That's one of the things I appreciate about open-source software. You have the freedom to choose where and how to run it.&lt;/p&gt;

&lt;p&gt;You might deploy LavinMQ on a virtual machine, in a container, or on infrastructure you already manage.&lt;/p&gt;

&lt;p&gt;And for many developers, especially when building a prototype or a small application, getting a broker running is relatively straightforward.&lt;/p&gt;

&lt;p&gt;But what happens when that application becomes important to your business?&lt;/p&gt;

&lt;h2&gt;
  
  
  The broker is free. Your time isn't.
&lt;/h2&gt;

&lt;p&gt;Installing a message broker is one thing. Keeping it reliable in production is another.&lt;/p&gt;

&lt;p&gt;Once your application depends on messaging, there are several things you need to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring:&lt;/strong&gt; Are queues growing faster than consumers can process messages? Are memory or disk resources becoming a problem?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability:&lt;/strong&gt; What happens if the broker or the machine running it becomes unavailable?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recovery:&lt;/strong&gt; How quickly can your messaging system recover after a failure?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgrades:&lt;/strong&gt; How do you apply updates while minimizing disruption?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Who can connect to the broker, and what are they allowed to access?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaling:&lt;/strong&gt; What happens when message volume increases beyond what your current setup can comfortably handle?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these challenges is impossible to solve.&lt;/p&gt;

&lt;p&gt;If you have an experienced infrastructure team, managing your own broker might be exactly what you want.&lt;/p&gt;

&lt;p&gt;But if you're a small development team, every hour spent investigating infrastructure is an hour you could have spent improving your application.&lt;/p&gt;

&lt;p&gt;That's the trade-off I find interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open source can remove software licensing costs, but it doesn't remove operational responsibilities.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What about clustering and high availability?
&lt;/h2&gt;

&lt;p&gt;Let's say your application initially runs with a single message broker.&lt;/p&gt;

&lt;p&gt;Everything works well until that broker becomes unavailable.&lt;/p&gt;

&lt;p&gt;Now your application may be unable to publish new messages or consume existing ones until connectivity is restored.&lt;/p&gt;

&lt;p&gt;Depending on your requirements, you might consider a multi-node setup to improve availability.&lt;/p&gt;

&lt;p&gt;But running a cluster introduces another set of questions.&lt;/p&gt;

&lt;p&gt;How do you handle node failures? Which queues are replicated? How do clients reconnect? What happens during maintenance? And how do you know whether the cluster is healthy?&lt;/p&gt;

&lt;p&gt;A cluster can improve availability, but it doesn't automatically make an application reliable.&lt;/p&gt;

&lt;p&gt;Your application still needs to handle connection interruptions, message acknowledgements, retries, and potentially duplicate processing.&lt;/p&gt;

&lt;p&gt;These are application-level responsibilities, regardless of whether you operate the broker yourself or use a managed service.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes with a managed message broker?
&lt;/h2&gt;

&lt;p&gt;This is where managed services become interesting.&lt;/p&gt;

&lt;p&gt;I work with LavinMQ at 84codes, the company behind CloudAMQP, so I should be transparent about my connection to the products I'm discussing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cloudamqp.com/" rel="noopener noreferrer"&gt;CloudAMQP&lt;/a&gt; provides managed LavinMQ and RabbitMQ.&lt;/p&gt;

&lt;p&gt;Instead of deploying and maintaining the message broker yourself, you can create a managed instance and connect your application to it.&lt;/p&gt;

&lt;p&gt;The idea is simple: you focus on how messaging works in your application, while the provider takes care of much of the underlying infrastructure.&lt;/p&gt;

&lt;p&gt;For example, CloudAMQP provides monitoring, alarms, managed maintenance, and cluster configurations for workloads that need higher availability.&lt;/p&gt;

&lt;p&gt;It also offers 24/7 technical support, which can be particularly valuable when you're dealing with an unexpected production issue.&lt;/p&gt;

&lt;p&gt;Of course, managed doesn't mean you can forget about reliability.&lt;/p&gt;

&lt;p&gt;You still need to design your producers and consumers properly, understand message delivery guarantees, and decide how your application should respond to failures.&lt;/p&gt;

&lt;p&gt;The difference is that you don't have to take responsibility for every operational detail of the broker itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it matter which cloud you're using?
&lt;/h2&gt;

&lt;p&gt;I think it does.&lt;/p&gt;

&lt;p&gt;Imagine your application is already running on AWS.&lt;/p&gt;

&lt;p&gt;Would you want your message broker hosted somewhere completely unrelated, with unnecessary network distance between your services?&lt;/p&gt;

&lt;p&gt;Probably not, unless you have a good reason.&lt;/p&gt;

&lt;p&gt;Network latency, connectivity, data location, and infrastructure requirements can all influence where you deploy your broker.&lt;/p&gt;

&lt;p&gt;CloudAMQP offers deployments on AWS, Google Cloud, Azure, DigitalOcean, and Scaleway, allowing teams to choose a cloud provider and region that fit their applications.&lt;/p&gt;

&lt;p&gt;This is useful because choosing a managed message broker doesn't necessarily mean changing the cloud platform where the rest of your application runs.&lt;/p&gt;

&lt;p&gt;Still, it's worth evaluating the actual network architecture, security requirements, and costs rather than assuming that choosing the same cloud provider solves everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability is a shared responsibility
&lt;/h2&gt;

&lt;p&gt;There's one point I particularly want to emphasize.&lt;/p&gt;

&lt;p&gt;Whether you're using self-hosted LavinMQ, RabbitMQ, or a managed message broker, &lt;strong&gt;reliable messaging doesn't happen automatically.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider a consumer that receives a message, processes it successfully, but loses its connection before acknowledging it.&lt;/p&gt;

&lt;p&gt;The broker may deliver that message again.&lt;/p&gt;

&lt;p&gt;If your application isn't prepared for duplicate delivery, the same operation could be performed twice.&lt;/p&gt;

&lt;p&gt;In a banking application, for example, that could be a serious problem.&lt;/p&gt;

&lt;p&gt;This is why concepts such as acknowledgements, idempotency, retries, and dead-letter queues are important.&lt;/p&gt;

&lt;p&gt;A managed service can help with infrastructure availability and operations. But it cannot replace good application design.&lt;/p&gt;

&lt;p&gt;I recently explored some of these failure scenarios while building a small banking demo using LavinMQ and two Node.js AMQP clients.&lt;/p&gt;

&lt;p&gt;The exercise reminded me that connection recovery and message-processing reliability are related, but they're not the same problem.&lt;/p&gt;

&lt;p&gt;You need to think about both.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, should you self-host or use a managed service?
&lt;/h2&gt;

&lt;p&gt;I don't think there's one correct answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-hosting might make sense when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want full control over your infrastructure and configuration.&lt;/li&gt;
&lt;li&gt;You already have the experience and resources to operate message brokers.&lt;/li&gt;
&lt;li&gt;You have specific deployment or compliance requirements.&lt;/li&gt;
&lt;li&gt;You're experimenting, learning, or running a workload that doesn't justify a managed service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A managed service might make sense when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want to spend more time developing your application.&lt;/li&gt;
&lt;li&gt;Your team has limited infrastructure capacity.&lt;/li&gt;
&lt;li&gt;You need operational support, monitoring, and managed maintenance.&lt;/li&gt;
&lt;li&gt;You prefer to delegate broker operations while keeping responsibility for your application architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cost matters too.&lt;/p&gt;

&lt;p&gt;A managed service has a price, while self-hosting has infrastructure and operational costs that are sometimes less obvious.&lt;/p&gt;

&lt;p&gt;It's worth comparing both rather than assuming one is always cheaper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mind your business
&lt;/h2&gt;

&lt;p&gt;The title might sound a little funny, but there's a serious point behind it.&lt;/p&gt;

&lt;p&gt;I don't mean developers should stop caring about infrastructure.&lt;/p&gt;

&lt;p&gt;Quite the opposite.&lt;/p&gt;

&lt;p&gt;If your application depends on messaging, you should understand how your broker works, how messages are delivered, and what happens when things fail.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;understanding your infrastructure and operating every part of it yourself are two different things.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes self-hosting is the right choice.&lt;/p&gt;

&lt;p&gt;Sometimes delegating the operational work gives your team more time to build what matters to your users.&lt;/p&gt;

&lt;p&gt;And sometimes the right decision changes as your application grows.&lt;/p&gt;

&lt;p&gt;I'm curious how other developers approach this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you prefer self-hosting your message brokers or using managed services? What influences your decision most: cost, control, reliability, or operational effort?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd love to hear about your experience, especially if you've tried both approaches.&lt;/p&gt;




&lt;h3&gt;
  
  
  Further reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/cloudamqp/lavinmq" rel="noopener noreferrer"&gt;LavinMQ on GitHub&lt;/a&gt; — Explore the open-source broker.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lavinmq.com/documentation" rel="noopener noreferrer"&gt;LavinMQ documentation&lt;/a&gt; — Learn about configuration and messaging features.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cloudamqp.com/" rel="noopener noreferrer"&gt;CloudAMQP&lt;/a&gt; — Learn about managed LavinMQ and RabbitMQ.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>opensource</category>
      <category>architecture</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Migrating a LavinMQ Node.js app from `amqplib` to `amqp-client.js`</title>
      <dc:creator>Hailay Gebreslasie Gebremeskel</dc:creator>
      <pubDate>Wed, 07 Oct 2026 16:02:26 +0000</pubDate>
      <link>https://dev.to/hailay/migrating-a-lavinmq-nodejs-app-from-amqplib-to-amqp-clientjs-4o63</link>
      <guid>https://dev.to/hailay/migrating-a-lavinmq-nodejs-app-from-amqplib-to-amqp-clientjs-4o63</guid>
      <description>&lt;p&gt;If you have an existing Node.js application using &lt;code&gt;amqplib&lt;/code&gt;, changing AMQP clients might sound like rewriting a large part of your application.&lt;/p&gt;

&lt;p&gt;I wanted to see how much actually had to change.&lt;/p&gt;

&lt;p&gt;I built a small banking application that publishes transactions to LavinMQ, processes them in a worker, retries temporary failures, dead-letters permanent failures, and protects against duplicate processing.&lt;/p&gt;

&lt;p&gt;The application separates the banking logic from the client-specific messaging code through a &lt;code&gt;broker.js&lt;/code&gt; layer.&lt;/p&gt;

&lt;p&gt;I first implemented that layer with &lt;code&gt;amqplib&lt;/code&gt;, then migrated it to &lt;code&gt;amqp-client.js&lt;/code&gt;, an AMQP client developed by CloudAMQP.&lt;/p&gt;

&lt;p&gt;The interesting result was that &lt;strong&gt;most of the application didn't need to change&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What stayed the same?
&lt;/h2&gt;

&lt;p&gt;The migration didn't require any application redesign.&lt;/p&gt;

&lt;p&gt;The following parts stayed the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Banking logic&lt;/li&gt;
&lt;li&gt;Queue and exchange topology&lt;/li&gt;
&lt;li&gt;Retry strategy&lt;/li&gt;
&lt;li&gt;Dead-letter handling&lt;/li&gt;
&lt;li&gt;Idempotency logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The worker still makes the same application-level decisions: process the transaction, retry a temporary failure, dead-letter a permanent failure, or acknowledge a transaction that has already been processed.&lt;/p&gt;

&lt;p&gt;The client-specific messaging operations are kept behind &lt;code&gt;broker.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Conceptually, the application looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application logic
       |
       v
   broker.js
       |
       v
  AMQP client
       |
       v
    LavinMQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation became particularly useful when I started replacing one AMQP client with the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually changed?
&lt;/h2&gt;

&lt;p&gt;Most of the changes were isolated to &lt;code&gt;broker.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's where the differences between the two clients became much clearer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Establishing connections&lt;/li&gt;
&lt;li&gt;Publishing messages&lt;/li&gt;
&lt;li&gt;Consuming messages&lt;/li&gt;
&lt;li&gt;Acknowledging messages&lt;/li&gt;
&lt;li&gt;Managing connection recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, the worker can interact with the broker through the same small interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;broker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;broker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When processing a transaction, it can also use operations such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;broker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;broker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToDeadQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;retries&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;broker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;acknowledge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The worker decides &lt;strong&gt;what should happen&lt;/strong&gt; to a transaction.&lt;/p&gt;

&lt;p&gt;The broker layer handles &lt;strong&gt;how the corresponding messaging operation is performed&lt;/strong&gt; using the AMQP client.&lt;/p&gt;

&lt;p&gt;That meant I could change the implementation behind &lt;code&gt;broker.js&lt;/code&gt; without redesigning the banking application's reliability logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connection recovery was the biggest difference
&lt;/h2&gt;

&lt;p&gt;Connection recovery was where I noticed the biggest difference between the two approaches.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;amqplib&lt;/code&gt;, I handled recovery in the broker layer.&lt;/p&gt;

&lt;p&gt;When the connection is lost, the application needs to detect the closed connection, reconnect, create a new channel, and restore the consumer.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connection lost
      |
      v
Detect connection close
      |
      v
Wait and reconnect
      |
      v
Create a new channel
      |
      v
Restore the consumer
      |
      v
Continue processing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but the application owns the recovery behavior.&lt;/p&gt;

&lt;p&gt;With the high-level &lt;code&gt;AMQPSession&lt;/code&gt; API in &lt;code&gt;amqp-client.js&lt;/code&gt;, more of that connection lifecycle is handled by the client.&lt;/p&gt;

&lt;p&gt;The session can reconnect when the connection is interrupted and restore its subscriptions after the connection is recovered.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connection lost
      |
      v
AMQPSession detects it
      |
      v
Reconnect
      |
      v
Restore subscription
      |
      v
Continue processing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important difference isn't that one client can recover and the other cannot.&lt;/p&gt;

&lt;p&gt;Both can be used to build an application that recovers from connection failures.&lt;/p&gt;

&lt;p&gt;The difference is &lt;strong&gt;where the responsibility for recovery lives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;amqplib&lt;/code&gt;, I implemented it in the broker layer.&lt;/p&gt;

&lt;p&gt;With the high-level &lt;code&gt;AMQPSession&lt;/code&gt; API, connection and subscription recovery are handled by the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability didn't move into the client
&lt;/h2&gt;

&lt;p&gt;One thing I found particularly interesting was that changing clients didn't change most of the reliability patterns in the application.&lt;/p&gt;

&lt;p&gt;Retries were still retries.&lt;/p&gt;

&lt;p&gt;Dead-lettering was still dead-lettering.&lt;/p&gt;

&lt;p&gt;Messages still needed acknowledgements.&lt;/p&gt;

&lt;p&gt;Queues still needed the appropriate durability settings.&lt;/p&gt;

&lt;p&gt;Transactions still needed to be processed idempotently to protect against duplicate delivery.&lt;/p&gt;

&lt;p&gt;Those concerns weren't suddenly solved by changing the AMQP client.&lt;/p&gt;

&lt;p&gt;The major difference I observed was how much connection lifecycle management the application had to handle itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The main takeaway
&lt;/h2&gt;

&lt;p&gt;The migration reinforced something I hadn't fully appreciated when I started the experiment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Changing an AMQP client doesn't necessarily mean changing your application's reliability design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By keeping client-specific messaging code behind a broker layer, I could migrate from &lt;code&gt;amqplib&lt;/code&gt; to &lt;code&gt;amqp-client.js&lt;/code&gt; without rewriting the banking logic.&lt;/p&gt;

&lt;p&gt;The business behavior remained the same.&lt;/p&gt;

&lt;p&gt;The messaging architecture remained the same.&lt;/p&gt;

&lt;p&gt;The implementation behind &lt;code&gt;broker.js&lt;/code&gt; changed.&lt;/p&gt;

&lt;p&gt;I wrote a full step-by-step migration guide covering the changes to connections, publishing, consuming, acknowledgements, and connection recovery:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.cloudamqp.com/blog/lavinmq-nodejs-migration/" rel="noopener noreferrer"&gt;Read the full migration guide on CloudAMQP&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The complete banking demo contains both implementations if you want to compare the code or run the experiment yourself:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/cloudamqp/lavinmq-demos/tree/main/nodejs-clients-demo" rel="noopener noreferrer"&gt;View the Node.js clients demo on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd be interested to hear how others approach this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where does connection recovery live in your Node.js messaging applications — in your application code, a wrapper around the client, or the client library itself?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if you've migrated between AMQP clients before, what part of the migration caused the most work?&lt;/p&gt;

&lt;p&gt;Feel free to leave questions about the implementation too.&lt;/p&gt;

</description>
      <category>lavinmq</category>
      <category>messaging</category>
      <category>node</category>
      <category>pubsub</category>
    </item>
  </channel>
</rss>
