如何确保已在Azure函数中成功处理队列消息?
我有一个C#Azure Functions(在应用程序服务计划中)应用程序,它使用HTTP触发器和队列触发器构建。该应用程序的工作原理是在客户机上安装一个脚本,该脚本使用SQL查询从客户机数据库提取各种文件,并将输出移动到临时Azure Blob存储。完成每个文件后,将调用一个HTTP触发器,该触发器为队列触发器创建一个队列消息,以拾取消息并将文件从临时blob存储移动到blob存储中的永久位置。HTTP触发器完成并将消息放入队列后,执行返回到客户机脚本以开始处理下一个SQL查询 我担心的是,当队列触发器实际仍在工作或可能失败时,这些队列消息会堆积起来,并且客户端脚本将以错误的成功消息完成,特别是在并行处理多个客户端时。在继续下一个SQL查询之前,是否有方法确保队列消息已成功处理 编辑:添加代码示例 我可能有3个客户端,在它们的机器上安装了一个应用程序,每个客户端设置为在上午12点执行这些脚本,并且可以并发运行,因为它们托管在客户端机器上。 客户端脚本如何确保已在Azure函数中成功处理队列消息?,azure,azure-functions,azure-webjobs,azure-queues,azure-http-trigger,Azure,Azure Functions,Azure Webjobs,Azure Queues,Azure Http Trigger,我有一个C#Azure Functions(在应用程序服务计划中)应用程序,它使用HTTP触发器和队列触发器构建。该应用程序的工作原理是在客户机上安装一个脚本,该脚本使用SQL查询从客户机数据库提取各种文件,并将输出移动到临时Azure Blob存储。完成每个文件后,将调用一个HTTP触发器,该触发器为队列触发器创建一个队列消息,以拾取消息并将文件从临时blob存储移动到blob存储中的永久位置。HTTP触发器完成并将消息放入队列后,执行返回到客户机脚本以开始处理下一个SQL查询 我担心的是,当
// perform SQL query to extract data from client database
// move extracted data to temporary Storage Blob hosted on the App Service storage account
return await httpClient.PostAsync(uri of the file in temporary blob storage)
// after all jobs for a client have been submitted by HTTP
// get storage account credentials
// write message to a queue "client-tasks-completed"
// queue message contains client name in the message
// initialVisibilityDelay set to 2 minutes
// this ensures queue has finished processing the files
当文件准备好进行处理时,第一个等待发送到HTTP。
Azure函数HTTP触发器
// get storage account credentials
// write message to storage queue "job-submissions'
return new OkResult();
// pick up message from "job-submissions" queue
// use the Microsoft.Azure.Storage.Blob library to move files
// to a permanent spot in the data lake
// create meta file with info about the file
// meta file contains info for when the extraction started and completed
// delete the temporary file
// job completed and the next queue message can be picked up
# pick up message from "client-tasks-completed" queue
if 'client1' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
elif 'client2' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
elif 'client3' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
现在,“作业提交”队列中有来自多个客户端的文件。
Azure函数队列触发器
// get storage account credentials
// write message to storage queue "job-submissions'
return new OkResult();
// pick up message from "job-submissions" queue
// use the Microsoft.Azure.Storage.Blob library to move files
// to a permanent spot in the data lake
// create meta file with info about the file
// meta file contains info for when the extraction started and completed
// delete the temporary file
// job completed and the next queue message can be picked up
# pick up message from "client-tasks-completed" queue
if 'client1' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
elif 'client2' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
elif 'client3' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
所以问题是,当HTTP触发器向队列写入消息时,我无法知道队列已经完成了对文件的处理。现在这不是一个大问题,因为这个过程发生得太快了,当我在HTTP触发器中向队列发送消息时,队列处理文件最多只需要几秒钟。我想知道单个作业何时完成的原因是,我在客户端脚本中有最后一步:
客户端脚本
// perform SQL query to extract data from client database
// move extracted data to temporary Storage Blob hosted on the App Service storage account
return await httpClient.PostAsync(uri of the file in temporary blob storage)
// after all jobs for a client have been submitted by HTTP
// get storage account credentials
// write message to a queue "client-tasks-completed"
// queue message contains client name in the message
// initialVisibilityDelay set to 2 minutes
// this ensures queue has finished processing the files
然后,一个单独的Python Azure函数侦听该队列以进行进一步处理:
Python队列触发器
// get storage account credentials
// write message to storage queue "job-submissions'
return new OkResult();
// pick up message from "job-submissions" queue
// use the Microsoft.Azure.Storage.Blob library to move files
// to a permanent spot in the data lake
// create meta file with info about the file
// meta file contains info for when the extraction started and completed
// delete the temporary file
// job completed and the next queue message can be picked up
# pick up message from "client-tasks-completed" queue
if 'client1' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
elif 'client2' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
elif 'client3' == queue_msg['ClientName']:
# standardize information within the files and write to our Azure SQL database
Python Azure函数在消费计划中,其batchSize
设置为1
,因为客户端文件有时可能很大,我不想超过1.5GB内存限制。所以我有两个问题,第一个是如何知道第一个队列触发器完成了它的工作?第二个问题是,如何确保Python QueueTrigger不会开始累积消息?我认为这两个问题都可以通过为侦听相同队列的两个队列触发器创建单独的Azure函数来解决。这将减轻双方的负担,但我不确定这是否是最佳做法。请参阅我的问题,我在这里询问了关于问题2的更多指导:更新:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Threading;
namespace FunctionApp31
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
string a = "111";
a=XX(a).Result;
return new OkObjectResult(a);
}
public static async Task<string> XX(string x)
{
await Task.Run(()=>{
Thread.Sleep(3000);
x = x + "222";
Console.WriteLine(x);
}
);
return x;
}
}
}
使用系统;
使用System.IO;
使用System.Threading.Tasks;
使用Microsoft.AspNetCore.Mvc;
使用Microsoft.Azure.WebJobs;
使用Microsoft.Azure.WebJobs.Extensions.Http;
使用Microsoft.AspNetCore.Http;
使用Microsoft.Extensions.Logging;
使用Newtonsoft.Json;
使用系统线程;
命名空间函数PP31
{
公共静态类函数1
{
[功能名称(“功能1”)]
公共静态异步任务运行(
[HttpTrigger(AuthorizationLevel.Function,“get”,“post”,Route=null)]HttpRequest请求,
ILogger日志)
{
字符串a=“111”;
a=XX(a)。结果;
返回新的OkObjectResult(a);
}
公共静态异步任务XX(字符串x)
{
等待任务。运行(()=>{
睡眠(3000);
x=x+“222”;
控制台写入线(x);
}
);
返回x;
}
}
}
原始答案:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Threading;
namespace FunctionApp31
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
string a = "111";
a=XX(a).Result;
return new OkObjectResult(a);
}
public static async Task<string> XX(string x)
{
await Task.Run(()=>{
Thread.Sleep(3000);
x = x + "222";
Console.WriteLine(x);
}
);
return x;
}
}
}
我建议您按顺序执行处理逻辑,而不是异步执行。或者,您可以在返回之前等待异步操作完成,以便在返回成功之前确保执行成功。(这可以避免在队列仍在处理时返回结果,如您在注释中所述。)
我注意到你问了一个新问题。我认为您可以扩展实例,而不是创建多功能应用程序。(当然,创建多功能应用程序没有问题)如果您基于消费计划,实例将根据负载自动伸缩。通常,当队列触发失败时,Azure功能将引发异常。你担心的情况听起来有点紧张。你能发布一些虚假成功消息的截图吗@当HTTP触发器向队列发送消息时,它被标记为“成功”。然后,当执行队列触发器时,它可能会失败。我想知道队列触发器是否成功完成。我想我可能需要使用一个持久函数,但是如果您没有完全执行queuetrigger的逻辑,那么queuetrigger没有成功执行,不是吗?让我重新表述一下这个问题。我并不担心queuetrigger能否成功执行。我知道它将在99%的时间内成功执行,如果没有,我可以在毒药队列中查找失败。我主要关心的是确保客户机应用程序知道queuetrigger已完成执行。我知道它大部分时间都会成功执行,但如果我有多个客户端同时运行,可能会有延迟。实际上,当队列仍在处理消息时,我可能会得到一个“成功”响应。您是否查看了持久功能。另外,查看事件网格和事件集线器如何等待异步操作完成