public static class QueueOperations
{
[FunctionName(“Support_ReprocessPoisonQueueMessages”)]
public static async Task Support_ReprocessPoisonQueueMessages([HttpTrigger(AuthorizationLevel.Admin, “put”, Route = “support/reprocessQueueMessages/{queueName}”)]HttpRequest req, ILogger log,
[Queue("{queueName}")] CloudQueue queue,
[Queue("{queueName}-poison")] CloudQueue poisonQueue, string queueName)
{
log.LogInformation(“Support_ReprocessPoisonQueueMessages function processed a request.”);
int.TryParse(req.Query["messageCount"], out var messageCountParameter);
var messageCount = messageCountParameter == 0 ? 10 : messageCountParameter;
var processedMessages = 0;
while (processedMessages < messageCount)
{
var message = await poisonQueue.GetMessageAsync();
if (message == null)
break;
var messageId = message.Id;
var popReceipt = message.PopReceipt;
await queue.AddMessageAsync(message); // a new Id and PopReceipt is assigned
await poisonQueue.DeleteMessageAsync(messageId, popReceipt);
processedMessages++;
}
return new OkObjectResult($"Reprocessed {processedMessages} messages from the {poisonQueue.Name} queue.");
}
}
// Prompt the user for the connection string
Console.WriteLine(“Enter the connection string for the Azure storage account:”);
var connectionString = Console.ReadLine();
// Prompt the user for the queue name
Console.WriteLine("Enter the name of the Azure Queue to unpoison:");
var queueName = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(connectionString) && !string.IsNullOrWhiteSpace(queueName))
{
// setup the connection to table storage
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(connectionString);
CloudQueueClient queueClient = cloudStorageAccount.CreateCloudQueueClient();
CloudQueue poisonQueue = queueClient.GetQueueReference(queueName + "-poison");
CloudQueue regularQueue = queueClient.GetQueueReference(queueName);
CloudQueueMessage retrievedMessage = poisonQueue.GetMessage();
while (retrievedMessage != null)
{
// delete the message from the poison queue
poisonQueue.DeleteMessage(retrievedMessage);
// queue up a new message on the original queue
regularQueue.AddMessage(retrievedMessage);
Console.WriteLine("Moved over message from poison queue: " + retrievedMessage.AsString);
// Get the next message for processing
retrievedMessage = poisonQueue.GetMessage();
}
}
else
{
Console.WriteLine("Unable to proceed without the connection string and queue name.");
}
public static class MonitorPoisonQueues
{
private static readonly TelemetryClient TelemetryClient = new TelemetryClient();
private static string key = TelemetryConfiguration.Active.InstrumentationKey
= Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY",
EnvironmentVariableTarget.Process);
[FunctionName("MonitorPoisonQueues")]
public static async Task Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, TraceWriter log)
{
var queuesToMonitor = new List<CloudQueue>();
var queueStorageConnectionString = ConfigurationManager.AppSettings["MonitorQueueStorage"];
var account = CloudStorageAccount.Parse(queueStorageConnectionString);
var queueClient = account.CreateCloudQueueClient();
QueueContinuationToken continuationToken = null;
do
{
var segment = await queueClient.ListQueuesSegmentedAsync(continuationToken);
var poisonQueues = segment.Results.Where(
q => q.Name.EndsWith("-poison", StringComparison.InvariantCultureIgnoreCase));
queuesToMonitor.AddRange(poisonQueues);
continuationToken = segment.ContinuationToken;
}
while (continuationToken != null);
foreach (var queue in queuesToMonitor)
{
await queue.FetchAttributesAsync();
var queueLength = queue.ApproximateMessageCount;
TelemetryClient.TrackMetric($"Poisonqueue length - {queue.Name}", (double)queueLength);
log.Info($"Queue: {queue.Name} (Items: {queueLength})");
}
}
}