public IEnumerable <QueueDescriptor> GetPrivateQueues(string machine, QueueTransaction xactionality) { // Get a list of queues with the specified category. return(MessageQueue.GetPrivateQueuesByMachine(machine).Where(x => ByTransactionality(xactionality, x.Transactional)).Select(x => new QueueDescriptor { Path = x.Path, Transactional = x.Transactional, Limit = x.MaximumQueueSize })); }
private async Task WaitForAcknowledgements(List <Tracking> sent) { if (sent.Count == 0) { return; } Console.Error.WriteLine($"DEBUG Waiting for {sent.Count} acknowledgements"); foreach (var item in sent) { try { await Sender.WaitForDeliveryAsync(item); _batchQueue.Lookup(Properties.LookupId, item.LookupId, timeout: TimeSpan.Zero, transaction: QueueTransaction.Single); } catch (AcknowledgmentException ex) { Console.Error.WriteLine("WARNING " + ex); using (var txn = new QueueTransaction()) { _batchQueue.MarkRejected(item.LookupId); // send a acknowledgement that the message has been rejected Queues.MoveMessage(_batchQueue, _posionQueue, item.LookupId, txn); txn.Commit(); } } catch (AggregateException ex) { //TODO: handle sent error to multi-element format name Console.Error.WriteLine($"WARNING multi-elements format names are not yet supported"); throw; } } }
public Task <Task> StartAsync() { _input = new QueueReader(_inputFormatName); if (Queues.IsTransactional(_input.FormatName) == QueueTransactional.Transactional) { _transaction = QueueTransaction.Single; } _running = RunAsync(); return(Task.FromResult(_running)); }
public async Task <Message> PeekAsync(Properties properties, QueueTransaction transaction) { Contract.Requires(transaction != null); var ht = _high.PeekAsync(properties); if (ht.IsCompleted || ht.IsFaulted) // always give high priority queue the first chance, it may complete synchronously { return(await ht); } var lt = _low.PeekAsync(properties); Message[] results = await Task.WhenAll(ht, lt); return(results.FirstOrDefault(m => m != null)); }
private void RouteBatch(List <Tracking> sent) { try { using (var txn = new QueueTransaction()) { RouteBatchCore(sent, txn); txn.Commit(); } } catch (RouteException ex) { Console.Error.WriteLine($"WARN {ex.Message} {{Destination={ex.Destination}}}"); BadMessageHandler(_input, ex.LookupId, QueueTransaction.Single); sent.Clear(); } }
private void MoveToUnroutableSubQueue(long lookupId, QueueTransaction transaction) { try { if (_posionSubQueue == null) { _posionSubQueue = new SubQueue(_input.FormatName + ";" + UnroutableSubQueue); } Queues.MoveMessage(_input, _posionSubQueue, lookupId, transaction); return; } catch (QueueException e) { Console.Error.WriteLine($"WARN Failed to move message {{lookupId={lookupId}}} {{subqueue={UnroutableSubQueue}}} {{error={e.Message}}}"); } }
private void MoveToPoisonSubqueue(QueueReader fromQueue, long lookupId, QueueTransaction transaction) { Contract.Requires(fromQueue != null); if (_posionQueue == null) { _posionQueue = new SubQueue(InputQueueFormatName + ";" + UnroutableSubQueue); } try { Queues.MoveMessage(fromQueue, _posionQueue, lookupId, transaction); return; } catch (QueueException e) { Console.Error.WriteLine($"WARN Failed to move message {{lookupId={lookupId}}} {{subqueue={UnroutableSubQueue}}} {{error={e.Message}}}"); } }
/// <summary> /// Posts a <paramref name="message"/> to the <paramref name="queue"/> with acknowledgement requested to be sent to <see cref="AdminQueueFormatName"/>. /// </summary> public Tracking RequestDelivery(Message message, QueueWriter queue, QueueTransaction transaction = null) { Contract.Requires(message != null); Contract.Requires(queue != null); Contract.Assert(_run != null); Contract.Assert(_adminQueue != null); message.AcknowledgmentTypes |= AcknowledgmentTypes.FullReachQueue; message.TimeToReachQueue = ReachQueueTimeout; message.AdministrationQueue = _adminQueue.FormatName; queue.Write(message, transaction); // acknowledgements for multicast messages get an empty DestinationQueue, so we need to remove it here var formatName = queue.FormatName.StartsWith("multicast=", StringComparison.OrdinalIgnoreCase)? "" : queue.FormatName; return(new Tracking(formatName, message.Id, message.LookupId)); }
protected void RouteBatchCore(List <Tracking> sent, QueueTransaction txn) { long lookupId = 0; LookupAction action = LookupAction.PeekFirst; for (int i = 0; i < MaxBatchSize; i++) { // peek for the next message var msg = _input.Lookup(Properties.All, lookupId, action, TimeSpan.Zero); if (msg == null) { break; } action = LookupAction.PeekNext; lookupId = msg.LookupId; // move to the batch subqueue so we know what we sent Queues.MoveMessage(_input, _batchQueue, msg.LookupId, txn); // route to message to the destination var dest = GetRoute(msg); sent.Add(Sender.RequestDelivery(msg, dest, txn)); } }
private static bool ByTransactionality(QueueTransaction xactionality, bool queueTransactional) { return xactionality == QueueTransaction.Transactional ? queueTransactional : (xactionality == QueueTransaction.NonTransactional ? !queueTransactional : true); }
public IEnumerable<QueueDescriptor> GetPublicQueuesByMachine(string machine, QueueTransaction xactionality) { return MessageQueue.GetPublicQueuesByMachine(machine).Where(x=> ByTransactionality(xactionality, x.Transactional) ).Select(x => new QueueDescriptor { Path = x.Path, Transactional = x.Transactional, Limit = x.MaximumQueueSize }); }
public IEnumerable<QueueDescriptor> GetPrivateQueues(string machine, QueueTransaction xactionality) { // Get a list of queues with the specified category. return MessageQueue.GetPrivateQueuesByMachine(machine).Where(x => ByTransactionality(xactionality, x.Transactional)).Select(x => new QueueDescriptor { Path = x.Path, Transactional = x.Transactional, Limit = x.MaximumQueueSize }); }
/// <summary> /// Sends a <paramref name="message"/> to the <paramref name="queue"/> and waits for it to be delivered. /// Waits for responses from all queues when the <paramref name="queue"/> is a multi-element format name. /// Note that the transaction MUST commit before the acknowledgements are received. /// </summary> /// <returns>Task that completes when the message has been delivered</returns> /// <exception cref="TimeoutException">Thrown if the message does not reach the queue before the <see cref="ReachQueueTimeout"/> has been reached</exception> /// <exception cref="AcknowledgmentException">Thrown if something bad happens, e.g. message could not be sent, access denied, the queue was purged, etc</exception> public static Task DeliverAsync(this QueueWriter queue, Message message, Postman postman, QueueTransaction transaction = null) { Contract.Requires(queue != null); Contract.Requires(message != null); Contract.Requires(postman != null); Contract.Requires(transaction == null || transaction == QueueTransaction.None || transaction == QueueTransaction.Single); var t = postman.RequestDelivery(message, queue, transaction); return(postman.WaitForDeliveryAsync(t)); }
public static Tracking RequestDelivery(this QueueWriter queue, Message message, Postman postman, QueueTransaction txn = null) => postman.RequestDelivery(message, queue, txn);
/// <summary>Tries to receive a message from the queue</summary> /// <remarks>Within a transaction you cannot receive a message that you moved to a subqueue</remarks> /// <param name="properties">The properties to read</param> /// <param name="timeout">The time allowed, defaults to infinite. Use <see cref="F:System.TimeSpan.Zero" /> to return without waiting</param> /// <param name="transaction">can be NULL for no transaction, a <see cref="T:BusterWood.Msmq.QueueTransaction" />, <see cref="F:BusterWood.Msmq.QueueTransaction.Single" />, or <see cref="F:BusterWood.Msmq.QueueTransaction.Dtc" />.</param> /// <returns>The message, or NULL if the receive times out</returns> public Message Read(Properties properties = Properties.All, TimeSpan?timeout = default(TimeSpan?), QueueTransaction transaction = null) { for (;;) { var msg = _queueReader.Read(properties | Properties.Label, timeout); var hash = ComputeHash(msg); var existingHash = _hashByLabel[msg.Label]; if (hash == existingHash) { Console.Error.WriteLine($"Dropping duplicate message for label '{msg.Label}'"); continue; } _hashByLabel[msg.Label] = hash; return(msg); } }
/// <summary>Tries to read the current message from the queue without removing the message from the queue.</summary> /// <remarks>Within a transaction you cannot peek a message that you moved to a subqueue</remarks> /// <param name="properties">The properties to read</param> /// <param name="timeout">The time allowed, defaults to infinite. Use <see cref="F:System.TimeSpan.Zero" /> to return without waiting</param> /// <param name="transaction">can be NULL for no transaction, a <see cref="T:BusterWood.Msmq.QueueTransaction" />, <see cref="F:BusterWood.Msmq.QueueTransaction.Single" />, or <see cref="F:BusterWood.Msmq.QueueTransaction.Dtc" />.</param> /// <returns>The message, or NULL if the receive times out</returns> public Message Peek(Properties properties = Properties.All, TimeSpan?timeout = default(TimeSpan?), QueueTransaction transaction = null) { return(_queueReader.Peek(properties, timeout, transaction)); }
private static bool ByTransactionality(QueueTransaction xactionality, bool queueTransactional) { return(xactionality == QueueTransaction.Transactional ? queueTransactional : (xactionality == QueueTransaction.NonTransactional ? !queueTransactional : true)); }
public IEnumerable <QueueDescriptor> GetPublicQueuesByMachine(string machine, QueueTransaction xactionality) { return(MessageQueue.GetPublicQueuesByMachine(machine).Where(x => ByTransactionality(xactionality, x.Transactional)).Select(x => new QueueDescriptor { Path = x.Path, Transactional = x.Transactional, Limit = x.MaximumQueueSize })); }
public Message Lookup(Properties properties, long lookupId, QueueTransaction transaction, LookupAction action = LookupAction.ReceiveCurrent, TimeSpan?timeout = null) { Contract.Requires(transaction != null); return(_high.Lookup(properties, lookupId, action, timeout, transaction) ?? _low.Lookup(properties, lookupId, action, timeout, transaction)); }
/// <summary>Read without waiting, returns null if no message is available in high or low priority subqueues</summary> public Message Read(Properties properties, QueueTransaction transaction) { Contract.Requires(transaction != null); return(_high.Read(properties, TimeSpan.Zero, transaction) ?? _low.Read(properties, TimeSpan.Zero, transaction)); }