{"id":269,"date":"2018-04-26T10:11:53","date_gmt":"2018-04-26T09:11:53","guid":{"rendered":"https:\/\/www.cogin.com\/blog\/?p=269"},"modified":"2018-04-26T10:42:49","modified_gmt":"2018-04-26T09:42:49","slug":"developers-perspective-rabbitmq-for-msmq-users-part-6","status":"publish","type":"post","link":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/","title":{"rendered":"Developer&#8217;s perspective &#8211; RabbitMQ for MSMQ users, part 6"},"content":{"rendered":"<p>For the last part of this short series, let\u2019s take a glance at some conceptual differences between RabbitMQ and MSMQ from developer\u2019s point of view. We can\u2019t cover much in a\u00a0single blog post, so let\u2019s just mention few things to get you started.<\/p>\n<h2>Declaring queues and exchanges<\/h2>\n<p>Queues and exchanges in RabbitMQ are often temporary and not as long living as in MSMQ. What do I mean by that? In MSMQ, queue&#8217;s setup is usually multi-step process &#8211; you&#8217;re not only creating a\u00a0queue, but also configuring its properties and access rights. Because of that\u00a0it&#8217;s typical to do it from\u00a0management console and not from code. Once set up, queue often remains in MSMQ &#8220;forever&#8221;, i.e. until we manually delete it.<\/p>\n<p>With RabbitMQ, creating new queues can be simpler. I&#8217;ll just talk about queues here, but same things apply for exchanges as well. You just <strong>declare<\/strong> a queue, and it&#8217;s auto-created if doesn&#8217;t already exists. You don&#8217;t have to manually check whether a queue exists before the declaration. This alone doesn&#8217;t represent a significant saving over MSMQ way. Here&#8217;s where real difference lies &#8211; if you&#8217;re using policies to configure queue parameters, queue will automatically pick up these settings as it&#8217;s created. Also, user permissions are managed centrally too, with pattern-based matching. So, depending on how policies and user settings are set up, your newly created queue could be immediately\u00a0configured as it should be as soon as it&#8217;s created. Except for bindings, unless we use default AMQP exchange.<\/p>\n<p>RabbitMQ itself has support for temporary queues. We can declare a queue not to\u00a0be\u00a0<strong>durable<\/strong>, in which case it will exist only until the broker\u00a0is restarted. Even more, we can set it to\u00a0<strong>auto delete<\/strong> mode, where it gets automatically deleted as soon as it doesn&#8217;t have any more consumers. Or even use\u00a0<strong>exclusive<\/strong> mode, where it can be used only from the\u00a0same connection where it was created.<\/p>\n<p>RabbitMQ .Net client (and probably others as well) supports automatic recovery. In that mode, if there&#8217;s a network problem and connection is dropped, client will reconnect, but also declare again all queues, exchanges, binding, etc. which were declared previously.<\/p>\n<h2>Message acknowledgments<\/h2>\n<p>With MSMQ, you always communicated through local MSMQ service, even if destination was on another machine. MSMQ stored pending messages in outgoing queues and took care of failures and retries. With RabbitMQ it&#8217;s possible to communicate with broker\u00a0over the network, so there&#8217;s a\u00a0higher probability that something will go wrong and we have to take care of potential issues ourselves.<\/p>\n<p>RabbitMQ has ack\/nack mechanism which is used to communicate that message is dealt with correctly (ack &#8211; acknowledgment), or that there was some problem during operation (nack &#8211; negative acknowledgment). This is available both for sending and receiving messages. Also, some client libraries have built-in retry or reconnect mechanism. If not, we have to do it manually.<\/p>\n<h2>Sending messages<\/h2>\n<p>If you read <a href=\"https:\/\/www.cogin.com\/blog\/rabbitmq\/rabbitmq-exchanges-rabbitmq-for-msmq-users-part-2\/\">Part 2<\/a>\u00a0of this series where we discussed Exchanges, you know that we can&#8217;t send to a queue directly, we always send to exchange and then it passes messages around according to its parameters and bindings. There is a shortcut to this rule, by using AMQP default exchange which allows us to put destination name in routing key. Messages will go directly to that queue without us having to configure any bindings.<\/p>\n<h3>Mandatory messages<\/h3>\n<p>What happens if we send a\u00a0message to an exchange and it turns out it&#8217;s unroutable? Either exchange doesn&#8217;t have any bindings, or its bindings have filters (e.g. by routing key, header property, etc) and our message doesn&#8217;t match any of them. That message will be lost. In some cases we&#8217;re ok with that. Maybe message contains some temporary information and if nobody needs that info currently, it&#8217;s not a loss if message is deleted. However, if message shouldn&#8217;t be lost, and we want to know about these cases, we can set up\u00a0<strong>mandatory<\/strong> flag and we&#8217;ll get an error if it won&#8217;t reach any destination queue. Then we can deal with that situation.<\/p>\n<h3>Publisher confirms<\/h3>\n<p>Since &#8220;send&#8221; operation could involve multiple destination queues, even on multiple machines, RabbitMQ can give us confirmation on whether message reached all destination queues or not. We issue\u00a0<em>confirm.select <\/em>operation and RabbitMQ gives as ack or nack. If response is <strong>nack<\/strong>, we can either abandon publishing that message or try sending it again. Since ack requires that message reaches all destinations, it might be too slow to wait for it after each message. RabbitMQ gives us <em>delivery tag<\/em><em>\u00a0<\/em>for each message we send, and since it&#8217;s autoincrementing number we can use that to ask for confirmation for multiple messages. Something like &#8220;please confirm that all messages up to this delivery tag are correctly published&#8221;.<\/p>\n<h2>Consuming messages from a queue<\/h2>\n<p><span style=\"font-weight: 400;\">RabbitMQ doesn\u2019t have Peek operation like MSMQ. When you take out a message from a queue using BasicGet operation, it will immediately be invisible to all other receivers. However, it doesn\u2019t mean it\u2019s completely removed from a queue. Message is permanently removed only after we send Ack. It&#8217;s advisable to send Ack at the end of entire processing, e.g. after database and other operations are completed. <\/span><\/p>\n<p><span style=\"font-weight: 400;\">If we Nack that message manually, or if Nack happens automatically because of a timeout,\u00a0message\u00a0will be requeued &#8211; it will be visible and available again in a queue. We can also tell RabbitMQ not to\u00a0requeue and just delete it instead. There&#8217;s similar operation called reject (also with requeue or no requeue) but it works for a single message only. While ack\/nack can be issued for multiple messages at once, thus increasing performance.<\/span><\/p>\n<h3>Receiving by subscription (Push)<\/h3>\n<p>BasicGet is a manual (pull) way of consuming messages. We can also subscribe to a queue and RabbitMQ client library will trigger our code when a message arrives. This is not only API difference, but RabbitMQ treats subscriptions differently. For instance, &#8220;auto delete&#8221; queue will be deleted when there are no more consumers. However, it works only for subscribed consumers, not for BasicGet mode.<\/p>\n<h2>Where to go next<\/h2>\n<p>There&#8217;s a lot more to RabbitMQ than we could cover in this short series. Fortunately, it has excellent documentation:<\/p>\n<p><a href=\"https:\/\/www.rabbitmq.com\/getstarted.html\">Getting started tutorials<\/a><\/p>\n<p><a href=\"https:\/\/www.rabbitmq.com\/documentation.html\">RabbitMQ documentation<\/a><\/p>\n<p>Although RabbitMQ management console is quite good, it offers only very basic view of messages, without any additional operations. That&#8217;s where\u00a0<a href=\"https:\/\/www.cogin.com\/mq\/\">QueueExplorer<\/a>\u00a0helps (yep, our own product) \u2013 the best way to work with RabbitMQ during development, testing, or production usage.<\/p>\n<p><a href=\"https:\/\/www.cogin.com\/articles\/Introduction-to-RabbitMQ-for-MSMQ-users.php\">Links to all 6 parts<\/a> of this series.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For the last part of this short series, let\u2019s take a glance at some conceptual differences between RabbitMQ and MSMQ from developer\u2019s point of view. We can\u2019t cover much in a\u00a0single blog post, so let\u2019s just mention few things to get you started. Declaring queues and exchanges Queues and exchanges in RabbitMQ are often temporary [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,12],"tags":[5,13],"class_list":["post-269","post","type-post","status-publish","format-standard","hentry","category-msmq","category-rabbitmq","tag-msmq","tag-rabbitmq"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Developer&#039;s perspective - RabbitMQ for MSMQ users, part 6<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Developer&#039;s perspective - RabbitMQ for MSMQ users, part 6\" \/>\n<meta property=\"og:description\" content=\"For the last part of this short series, let\u2019s take a glance at some conceptual differences between RabbitMQ and MSMQ from developer\u2019s point of view. We can\u2019t cover much in a\u00a0single blog post, so let\u2019s just mention few things to get you started. Declaring queues and exchanges Queues and exchanges in RabbitMQ are often temporary [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/\" \/>\n<meta property=\"og:site_name\" content=\"Cogin blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-04-26T09:11:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-04-26T09:42:49+00:00\" \/>\n<meta name=\"author\" content=\"Dejan Grujic\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dejan Grujic\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/rabbitmq\\\/developers-perspective-rabbitmq-for-msmq-users-part-6\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/rabbitmq\\\/developers-perspective-rabbitmq-for-msmq-users-part-6\\\/\"},\"author\":{\"name\":\"Dejan Grujic\",\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/#\\\/schema\\\/person\\\/e0c4fd92043868daa052d5978d69ed22\"},\"headline\":\"Developer&#8217;s perspective &#8211; RabbitMQ for MSMQ users, part 6\",\"datePublished\":\"2018-04-26T09:11:53+00:00\",\"dateModified\":\"2018-04-26T09:42:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/rabbitmq\\\/developers-perspective-rabbitmq-for-msmq-users-part-6\\\/\"},\"wordCount\":1130,\"keywords\":[\"MSMQ\",\"RabbitMQ\"],\"articleSection\":[\"MSMQ\",\"RabbitMQ\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/rabbitmq\\\/developers-perspective-rabbitmq-for-msmq-users-part-6\\\/\",\"url\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/rabbitmq\\\/developers-perspective-rabbitmq-for-msmq-users-part-6\\\/\",\"name\":\"Developer's perspective - RabbitMQ for MSMQ users, part 6\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/#website\"},\"datePublished\":\"2018-04-26T09:11:53+00:00\",\"dateModified\":\"2018-04-26T09:42:49+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/#\\\/schema\\\/person\\\/e0c4fd92043868daa052d5978d69ed22\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/rabbitmq\\\/developers-perspective-rabbitmq-for-msmq-users-part-6\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.cogin.com\\\/blog\\\/rabbitmq\\\/developers-perspective-rabbitmq-for-msmq-users-part-6\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/rabbitmq\\\/developers-perspective-rabbitmq-for-msmq-users-part-6\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Developer&#8217;s perspective &#8211; RabbitMQ for MSMQ users, part 6\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/\",\"name\":\"Cogin blog\",\"description\":\"Queuing tools and articles\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/#\\\/schema\\\/person\\\/e0c4fd92043868daa052d5978d69ed22\",\"name\":\"Dejan Grujic\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7edfd9071a535694242755af2736da7972b73f5d026be6563586a9b0ff7829d0?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7edfd9071a535694242755af2736da7972b73f5d026be6563586a9b0ff7829d0?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7edfd9071a535694242755af2736da7972b73f5d026be6563586a9b0ff7829d0?s=96&d=mm&r=g\",\"caption\":\"Dejan Grujic\"},\"sameAs\":[\"http:\\\/\\\/www.cogin.com\"],\"url\":\"https:\\\/\\\/www.cogin.com\\\/blog\\\/author\\\/gruja\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Developer's perspective - RabbitMQ for MSMQ users, part 6","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/","og_locale":"en_US","og_type":"article","og_title":"Developer's perspective - RabbitMQ for MSMQ users, part 6","og_description":"For the last part of this short series, let\u2019s take a glance at some conceptual differences between RabbitMQ and MSMQ from developer\u2019s point of view. We can\u2019t cover much in a\u00a0single blog post, so let\u2019s just mention few things to get you started. Declaring queues and exchanges Queues and exchanges in RabbitMQ are often temporary [&hellip;]","og_url":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/","og_site_name":"Cogin blog","article_published_time":"2018-04-26T09:11:53+00:00","article_modified_time":"2018-04-26T09:42:49+00:00","author":"Dejan Grujic","twitter_misc":{"Written by":"Dejan Grujic","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/#article","isPartOf":{"@id":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/"},"author":{"name":"Dejan Grujic","@id":"https:\/\/www.cogin.com\/blog\/#\/schema\/person\/e0c4fd92043868daa052d5978d69ed22"},"headline":"Developer&#8217;s perspective &#8211; RabbitMQ for MSMQ users, part 6","datePublished":"2018-04-26T09:11:53+00:00","dateModified":"2018-04-26T09:42:49+00:00","mainEntityOfPage":{"@id":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/"},"wordCount":1130,"keywords":["MSMQ","RabbitMQ"],"articleSection":["MSMQ","RabbitMQ"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/","url":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/","name":"Developer's perspective - RabbitMQ for MSMQ users, part 6","isPartOf":{"@id":"https:\/\/www.cogin.com\/blog\/#website"},"datePublished":"2018-04-26T09:11:53+00:00","dateModified":"2018-04-26T09:42:49+00:00","author":{"@id":"https:\/\/www.cogin.com\/blog\/#\/schema\/person\/e0c4fd92043868daa052d5978d69ed22"},"breadcrumb":{"@id":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.cogin.com\/blog\/rabbitmq\/developers-perspective-rabbitmq-for-msmq-users-part-6\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.cogin.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Developer&#8217;s perspective &#8211; RabbitMQ for MSMQ users, part 6"}]},{"@type":"WebSite","@id":"https:\/\/www.cogin.com\/blog\/#website","url":"https:\/\/www.cogin.com\/blog\/","name":"Cogin blog","description":"Queuing tools and articles","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.cogin.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.cogin.com\/blog\/#\/schema\/person\/e0c4fd92043868daa052d5978d69ed22","name":"Dejan Grujic","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/7edfd9071a535694242755af2736da7972b73f5d026be6563586a9b0ff7829d0?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/7edfd9071a535694242755af2736da7972b73f5d026be6563586a9b0ff7829d0?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/7edfd9071a535694242755af2736da7972b73f5d026be6563586a9b0ff7829d0?s=96&d=mm&r=g","caption":"Dejan Grujic"},"sameAs":["http:\/\/www.cogin.com"],"url":"https:\/\/www.cogin.com\/blog\/author\/gruja\/"}]}},"_links":{"self":[{"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/posts\/269","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/comments?post=269"}],"version-history":[{"count":11,"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/posts\/269\/revisions"}],"predecessor-version":[{"id":352,"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/posts\/269\/revisions\/352"}],"wp:attachment":[{"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/media?parent=269"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/categories?post=269"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cogin.com\/blog\/wp-json\/wp\/v2\/tags?post=269"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}