繁体   English   中英

使用带有 C# 的持久函数添加单行时,在 Azure blob 表中创建了两个条目

[英]Two entries made in Azure blob table when adding a single row, using Durable Functions with C#

我正在研究概念验证,但我对 Azure 和 C# 都是新手。 下面的代码可以正常工作 - 它成功地将传入的 JSON 数据存储到 blob 表中。 问题是它每次都会创建 2 个不同的行,每个行都有自己唯一的 RowKey(我创建的 GUID),但是,如您所见,我只使用await GrooveData.AddAsync (data); .

我错过了什么? 这两行的时间戳略有不同。

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;

namespace Company.Function
{
    public static class GrooveOrchestrationTest
    {
        [FunctionName("GrooveOrchestrationTest")]
        public static async Task<List<string>> RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            [Table ("GrooveData")] IAsyncCollector<GrooveItem> GrooveData)
        {
            var outputs = new List<string>();
            GrooveItem data = context.GetInput<GrooveItem>();      

                // Indicate we got the data:
                outputs.Add(await context.CallActivityAsync<string>("NowProcessingMessage", data));
                
                // RowKey and PartitionKey are required by Azure, but we don't get them from Groove and must provide them:
                data.RowKey = Guid.NewGuid ().ToString ();
                data.PartitionKey = data.grooveevent;

                // and this stores the data:
                await GrooveData.AddAsync (data);

                //If we get this far, it probably worked :D
                outputs.Add(await context.CallActivityAsync<string>("GrooveDataTest", data));

            return outputs;
        }

        [FunctionName("NowProcessingMessage")]
        public static string ProcessingMessage([ActivityTrigger] GrooveItem cust, ILogger log)
        {
            log.LogInformation($"Now processing transaction for {cust.firstname} for {cust.amount}");
            return $"Trying to store transaction for {cust.firstname} for {cust.amount}";
        }

        //This works.  To use it, call it above in CallActivityAsync:
        [FunctionName("GrooveDataTest")]
        public static string ProcessGrooveData([ActivityTrigger] GrooveItem cust, ILogger log)
        {
            log.LogInformation($"Received transaction for {cust.firstname} {cust.lastname}: {cust.email}");
            return $"{cust.firstname} had type {cust.grooveevent} for {cust.product_name} for ${cust.amount}";
        
        }

        [FunctionName("GrooveDataHandlerTest_HttpStart")]
        public static async Task<HttpResponseMessage> HttpStart(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
            [DurableClient] IDurableOrchestrationClient starter,
            ILogger log)
        {
                        
            var data = await req.Content.ReadAsAsync<GrooveItem>();
            
            // Function input comes from the request content.
            string instanceId = await starter.StartNewAsync("GrooveOrchestrationTest", data);

            log.LogInformation($"Started orchestration with ID = '{instanceId}'.");

            return starter.CreateCheckStatusResponse(req, instanceId);
        }
    }
}

我正在使用 Postman 进行测试,发送 JSON 数据: {"event":"sales","buyer_first_name":"Testy","buyer_last_name":"2","buyer_email":"testy@bugmenot.com","product_name":"Great Product","amount":"99.99"}

这是我在 Visual Studio Code 中运行时的活动日志,据我所知,它只被调用一次:

[8/10/2020 2:19:08 PM] Executing 'GrooveOrchestrationTest' (Reason='', Id=064dd243-fccc-4d29-9c1e-b803d0aaf87f)
[8/10/2020 2:19:08 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'GrooveOrchestrationTest (Orchestrator)' started. IsReplay: False. Input: (2920 bytes). State: Started. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 3.
[8/10/2020 2:19:08 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'NowProcessingMessage (Activity)' scheduled. Reason: GrooveOrchestrationTest. IsReplay: False. State: Scheduled. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 4.
[8/10/2020 2:19:08 PM] Executed 'GrooveOrchestrationTest' (Succeeded, Id=064dd243-fccc-4d29-9c1e-b803d0aaf87f)
[8/10/2020 2:19:08 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'GrooveOrchestrationTest (Orchestrator)' awaited. IsReplay: False. State: Awaited. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 5.
[8/10/2020 2:19:08 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'NowProcessingMessage (Activity)' started. IsReplay: False. Input: (3088 bytes). State: Started. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 6.
[8/10/2020 2:19:08 PM] Executing 'NowProcessingMessage' (Reason='', Id=057e5131-f212-4234-a3ae-e2f504814146)
[8/10/2020 2:19:08 PM] Now processing transaction for Testy for 99.99
[8/10/2020 2:19:08 PM] Executed 'NowProcessingMessage' (Succeeded, Id=057e5131-f212-4234-a3ae-e2f504814146)
[8/10/2020 2:19:08 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'NowProcessingMessage (Activity)' completed. ContinuedAsNew: False. IsReplay: False. Output: (196 bytes). State: Completed. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 7.
[8/10/2020 2:19:08 PM] Executing 'GrooveOrchestrationTest' (Reason='', Id=9c7ae8df-8f48-451c-a021-7f54167f5be9)
[8/10/2020 2:19:08 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'GrooveDataTest (Activity)' scheduled. Reason: GrooveOrchestrationTest. IsReplay: False. State: Scheduled. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 8.
[8/10/2020 2:19:08 PM] Executed 'GrooveOrchestrationTest' (Succeeded, Id=9c7ae8df-8f48-451c-a021-7f54167f5be9)
[8/10/2020 2:19:09 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'GrooveOrchestrationTest (Orchestrator)' awaited. IsReplay: False. State: Awaited. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 9.
[8/10/2020 2:19:09 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'GrooveDataTest (Activity)' started. IsReplay: False. Input: (3236 bytes). State: Started. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 10.
[8/10/2020 2:19:09 PM] Executing 'GrooveDataTest' (Reason='', Id=8f70954c-64ac-48f5-83ce-ca3b89d11bcf)
[8/10/2020 2:19:09 PM] Received transaction for Testy 1: testy@bugmenot.com
[8/10/2020 2:19:09 PM] Executed 'GrooveDataTest' (Succeeded, Id=8f70954c-64ac-48f5-83ce-ca3b89d11bcf)
[8/10/2020 2:19:09 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'GrooveDataTest (Activity)' completed. ContinuedAsNew: False. IsReplay: False. Output: (204 bytes). State: Completed. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 11.
[8/10/2020 2:19:09 PM] Executing 'GrooveOrchestrationTest' (Reason='', Id=8656fff8-6b49-4fdd-93ef-38959e7af01f)
[8/10/2020 2:19:09 PM] 6ea660aef5924d0ebfe70d6dbfd52742: Function 'GrooveOrchestrationTest (Orchestrator)' completed. ContinuedAsNew: False. IsReplay: False. Output: (412 bytes). State: Completed. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.1.1. SequenceNumber: 12.
[8/10/2020 2:19:09 PM] Executed 'GrooveOrchestrationTest' (Succeeded, Id=8656fff8-6b49-4fdd-93ef-38959e7af01f)

更新我刚刚读到,Orchestrator 不应使用任何随机化,例如调用 GUID function,我正在这样做以创建 ROWKEY 值。 也许这是相关的? 我尝试将它移到 HTTPSTART 中,但这会产生一个它已经存在的实际错误。 也许还有另一种方法可以在不违反此限制的情况下将其放入项目中?

解决方案user1672994 提供的答案是正确的,但最初发布的方法#1 必须稍作调整才能正常工作。 这是固定的新代码:

        [FunctionName("AddGrooveDataAsync2")]
        public static async Task<String> Run([ActivityTrigger] GrooveItem trans, [Table ("GrooveData")] IAsyncCollector<GrooveItem> GrooveData, ILogger log)
        {
        // RowKey and PartitionKey are required by Azure, but we don't get them from Groove and must provide them:
            trans.RowKey = Guid.NewGuid ().ToString ();
            trans.PartitionKey = trans.grooveevent;

            // and this stores the data:
            await GrooveData.AddAsync (trans);
            return $"Added {trans.firstname} {trans.lastname}: {trans.email}";
        }

这里的问题是您正在通过 Orchestrator function 直接将数据添加到表中,这将被重放多次,直到完成。 您可以通过以下方法解决此问题。 我建议您使用方法1。

方法1:将逻辑转换为活动function,如果消息正在重播,则不会再次调用该活动。

    [FunctionName("AddGrooveDataAsync")]
    public static async Task<string> AddGrooveDataAsync([ActivityTrigger] GrooveItem cust, [Table ("GrooveData")] IAsyncCollector<GrooveItem> GrooveData, ILogger log)
    {
        // RowKey and PartitionKey are required by Azure, but we don't get them from Groove and must provide them:
            data.RowKey = Guid.NewGuid ().ToString ();
            data.PartitionKey = data.grooveevent;

            // and this stores the data:
            await GrooveData.AddAsync (data);
    }

方法 2:添加context.IsReplaying检查。

   [FunctionName("GrooveOrchestrationTest")]
    public static async Task<List<string>> RunOrchestrator(
        [OrchestrationTrigger] IDurableOrchestrationContext context,
        [Table ("GrooveData")] IAsyncCollector<GrooveItem> GrooveData)
    {
        var outputs = new List<string>();
        GrooveItem data = context.GetInput<GrooveItem>();      

            // Indicate we got the data:
            outputs.Add(await context.CallActivityAsync<string>("NowProcessingMessage", data));
             
            if (!context.IsReplaying)
            {
                  // RowKey and PartitionKey are required by Azure, but we don't get them from Groove and must provide them:
                  data.RowKey = Guid.NewGuid ().ToString ();
                  data.PartitionKey = data.grooveevent;
            }

            // and this stores the data:
            await GrooveData.AddAsync (data);

            //If we get this far, it probably worked :D
            outputs.Add(await context.CallActivityAsync<string>("GrooveDataTest", data));

        return outputs;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM