【问题标题】:ConcurrentQueue dequeue problem in Azure functionAzure 函数中的 ConcurrentQueue 出队问题
【发布时间】:2021-01-15 20:51:10
【问题描述】:

我已经声明了一个ConcurrentQueue 并添加了一个 GUID 列表。添加到队列中很好,但是当我从 TimerTrigger 函数内部访问队列时,它似乎是空的(updateQueue.count 为 0)。这种行为发生在云中,但是当我在本地执行相同的操作时,它可以正常工作。

public static class Function1
{
    private static readonly ConcurrentQueue<IEnumerable<Guid>> updateQueue = new ConcurrentQueue<IEnumerable<Guid>>();

    public static async Task<IActionResult> UpdateRun(
        [HttpTrigger(AuthorizationLevel.Admin, "post", Route = null)] HttpRequest req, ExecutionContext execContext)
    {
        logger.LogInformation($"FunctionUpdate Start");
        using var reader = new StreamReader(req.Body);
        var request = JsonConvert.DeserializeObject<IEnumerable<Request>>(reader.ReadToEnd());
        var correlationIds = request?.Select(s => s.CorrelationId);

        updateQueue.Enqueue(correlationIds);
        return new OkObjectResult(new Response { HttpStatusCode = HttpStatusCode.Accepted });
    }

    [FunctionName("FunctionHandleQueue"), Timeout("00:05:00")]
    public static async Task HandleQueue([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ExecutionContext execContext) // once every 1 minutes
    {
        logger.LogInformation($"before updateQueue condition : {updateQueue.Count}"); 
        if (updateQueue.Count > 0)
        {
            logger.LogInformation($"after updateQueue condition {updateQueue.Count}");

            var guids = new List<Guid>();
            var count = 0;
            while (count <= 1000 && updateQueue.Count > 0)
            {
                updateQueue.TryDequeue(out var updateRequest);
                var enumerable = updateRequest.ToList();
                count += enumerable.Count;
                guids.AddRange(enumerable);
            }

            await new ProcessUpdateSales(CreateMapper(), execContext)
                .Orchestrate(guids)
        }
    }
}

TimerTrigger 每 1 分钟执行一次时会创建日志:

更新队列之前条件:0

为什么updateQueue.Count 总是 0?我做错了什么?

【问题讨论】:

  • 虽然 Azure Functions 可能通常共享一个背板,但不能保证。资源可以随时停止或启动,功能的新副本可能无法访问原始状态。如果需要保留状态,请使用持久函数或实际队列,例如 Azure 存储队列。
  • 补充大卫的评论:它在您的机器上本地工作,因为只有一个本地应用程序域由函数的开发运行时启动,因此您可以从同一个队列对象中添加和删除。
  • 谢谢大卫和罗曼。所以你的意思是即使 updateQueue 仅特定于单个函数,但当 TimerTrigger 函数尝试访问时,不能保证 updateQueue 可用?
  • 正确。代码中的单个函数不会生成单个运行时函数:)。
  • @HuryShen 确定,很高兴!已添加。

标签: c# azure-functions concurrent-queue


【解决方案1】:

虽然 Azure Functions 通常可能共享一个背板,但不能保证。资源可以随时停止或启动,功能的新副本可能无法访问原始状态。因此,如果您使用静态字段在函数执行之间共享数据,它应该能够从外部源重新加载数据。

也就是说,由于 Azure Functions 的设计方式,这也不一定是可取的。 Azure Functions 通过动态可伸缩性实现高吞吐量。随着处理当前工作负载需要更多资源,可以自动配置它们以保持高吞吐量。

因此,在单个函数执行中做太多工作实际上会干扰整个系统吞吐量,因为函数背板无法提供额外的工作人员来处理负载。

如果您需要保留状态,请使用永久存储形式。这可以采用 Azure 持久函数、Azure 存储队列、Azure 服务总线队列甚至数据库的形式。此外,为了最好地利用函数的可扩展性,请尝试将工作负载减少到允许大量并行处理的可管理批处理。虽然您可能需要在单个操作中预先加载您的工作,但您希望后续处理尽可能精细。

【讨论】:

    猜你喜欢
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-04
    • 1970-01-01
    • 2014-05-09
    • 2019-08-17
    相关资源
    最近更新 更多