예제 #1
0
func (channel *Channel) nackBelow(tag uint64, requeue bool, commitTx bool) *amqp.AMQPError {
	channel.ackLock.Lock()
	defer channel.ackLock.Unlock()

	// Transaction mode
	if channel.txMode && !commitTx {
		channel.txLock.Lock()
		defer channel.txLock.Unlock()
		channel.txAcks = append(channel.txAcks, amqp.NewTxAck(tag, true, requeue, true))
		return nil
	}

	// Non-transaction mode
	var count = 0
	for k, unacked := range channel.awaitingAcks {
		if k <= tag || tag == 0 {
			count += 1
			// Init
			consumer, cFound := channel.consumers[unacked.ConsumerTag]
			queue, qFound := channel.server.queues[unacked.QueueName]

			// Initialize resource holders array
			var rhs = []amqp.MessageResourceHolder{channel}
			if cFound {
				rhs = append(rhs, consumer)
			}

			// requeue and release the approriate resources
			if requeue && qFound {
				// If we're requeueing we release the resources but don't remove the
				// reference.
				queue.Readd(unacked.QueueName, unacked.Msg)
				for _, rh := range rhs {
					rh.ReleaseResources(unacked.Msg)
				}
			} else {
				// If we aren't re-adding, remove the ref and all associated
				// resources
				err := channel.server.msgStore.RemoveRef(unacked.Msg, unacked.QueueName, rhs)
				if err != nil {
					return amqp.NewSoftError(500, err.Error(), 60, 120)
				}
			}

			// Remove this unacked message from the ones
			// we're waiting for acks on and ping the consumer
			// since there might be a message available now
			delete(channel.awaitingAcks, k)
			if cFound {
				consumer.Ping()
			}
		}
	}
	return nil
}
예제 #2
0
func (channel *Channel) recover(requeue bool) {
	if requeue {
		channel.ackLock.Lock()
		defer channel.ackLock.Unlock()
		// Requeue. Make sure we update stats
		for _, unacked := range channel.awaitingAcks {
			// re-add to queue
			queue, qFound := channel.server.queues[unacked.QueueName]
			if qFound {
				queue.Readd(unacked.QueueName, unacked.Msg)
			}
			// else: The queue gone. The reference would have been removed
			//       then so we don't remove it now in an else clause

			consumer, cFound := channel.consumers[unacked.ConsumerTag]
			// decr channel active
			channel.ReleaseResources(unacked.Msg)
			// decr consumer active
			if cFound {
				consumer.ReleaseResources(unacked.Msg)
			}
		}
		// Clear awaiting acks
		channel.awaitingAcks = make(map[uint64]amqp.UnackedMessage)
	} else {
		// Redeliver. Don't need to mess with stats.
		// We do this in a short-lived goroutine since this could end up
		// blocking on sending to the network inside the consumer
		go func() {
			for tag, unacked := range channel.awaitingAcks {
				consumer, cFound := channel.consumers[unacked.ConsumerTag]
				if cFound {
					// Consumer exists, try to deliver again
					channel.server.msgStore.IncrDeliveryCount(unacked.QueueName, unacked.Msg)
					consumer.Redeliver(tag, unacked.Msg)
				} else {
					// no consumer, drop message
					var rhs = []amqp.MessageResourceHolder{
						channel,
						consumer,
					}
					channel.server.msgStore.RemoveRef(unacked.Msg, unacked.QueueName, rhs)
				}

			}
		}()

	}
}