title: Dead lettering with php-amqplib and RabbitMQ?
body: <p>I'm just starting out in using php-amqplib and RabbitMQ and want a way to handle messages that, for whatever reason, can't be processed and are nack'd.  I thought that one way people handle this is with a dead letter queue.  I'm trying to set this up but have not had any luck so far and hope someone could offer some suggestions.</p>
  
  <p>My initiation of the queues looks a little something like:</p>
  
  <pre><code>class BaseAbstract
  {
      /** @var AMQPStreamConnection */
      protected $connection;
      /** @var AMQPChannel */
      protected $channel;
      /** @var array */
      protected $deadLetter = [
          'exchange' =&gt; 'dead_letter',
          'type' =&gt; 'direct',
          'queue' =&gt; 'delay_queue',
          'ttl' =&gt; 10000 // in milliseconds
      ];
  
      protected function initConnection(array $config)
      {
          try {
              $this-&gt;connection = AMQPStreamConnection::create_connection($config);
              $this-&gt;channel = $this-&gt;connection-&gt;channel();
  
              // Setup dead letter exchange and queue
              $this-&gt;channel-&gt;exchange_declare($this-&gt;deadLetter['exchange'], $this-&gt;deadLetter['type'], false, true, false);
              $this-&gt;channel-&gt;queue_declare($this-&gt;deadLetter['queue'], false, true, false, false, false, new AMQPTable([
                  'x-dead-letter-exchange' =&gt; $this-&gt;deadLetter['exchange'],
                  'x-dead-letter-routing-key' =&gt; $this-&gt;deadLetter['queue'],
                  'x-message-ttl' =&gt; $this-&gt;deadLetter['ttl']
              ]));
              $this-&gt;channel-&gt;queue_bind($this-&gt;deadLetter['queue'], $this-&gt;deadLetter['exchange']);
  
              // Set up regular exchange and queue
              $this-&gt;channel-&gt;exchange_declare($this-&gt;getExchangeName(), $this-&gt;getExchangeType(), true, true, false);
              $this-&gt;channel-&gt;queue_declare($this-&gt;getQueueName(), true, true, false, false, new AMQPTable([
                  'x-dead-letter-exchange' =&gt; $this-&gt;deadLetter['exchange'],
                  'x-dead-letter-routing-key' =&gt; $this-&gt;deadLetter['queue']
              ]));
  
              if (method_exists($this, 'getRouteKey')) {
                  $this-&gt;channel-&gt;queue_bind($this-&gt;getQueueName(), $this-&gt;getExchangeName(), $this-&gt;getRouteKey());
              } else {
                  $this-&gt;channel-&gt;queue_bind($this-&gt;getQueueName(), $this-&gt;getExchangeName());
              }
          } catch (\Exception $e) {
              throw new \RuntimeException('Cannot connect to the RabbitMQ service: ' . $e-&gt;getMessage());
          }
          return $this;
      }
  
      // ...
  }
  </code></pre>
  
  <p>which I thought should set up my dead letter exchange and queue, and then also set up my regular exchange and queue (with the getRouteKey, getQueueName, and getExchangeName/Type methods provided by extending classes)</p>
  
  <p>When I try to handle a message like:</p>
  
  <pre><code>public function process(AMQPMessage $message)
  {
      $msg = json_decode($message-&gt;body);
      if (empty($msg-&gt;payload) || empty($msg-&gt;payload-&gt;run)) {
          $message-&gt;delivery_info['channel']-&gt;basic_nack($message-&gt;delivery_info['delivery_tag'], false, true);
          return;
      }
  
      // removed for post brevity, but compose $cmd variable
  
      exec($cmd, $output, $returned);
      if ($returned !== 0) {
          $message-&gt;delivery_info['channel']-&gt;basic_ack($message-&gt;delivery_info['delivery_tag']);
      } else {
          $message-&gt;delivery_info['channel']-&gt;basic_nack($message-&gt;delivery_info['delivery_tag']);
      }
  }
  </code></pre>
  
  <p>But I get back the error <code>Something went wrong: Cannot connect to the RabbitMQ service: PRECONDITION_FAILED - inequivalent arg 'x-dead-letter-exchange' for queue 'delay_queue' in vhost '/': received 'dead_letter' but current is ''</code></p>
  
  <p>Is this the way I should be setting up dead lettering?  Different examples I've seen around all seem to show a bit of a different way of handling it, none of which seem to work for me.  So I've obviously misunderstood something here and am appreciative of any advice. :)</p>