1

因此,我正在对一些Azure Durable Functions进行原型设计,以尝试了解它们是否适合我们内部 API 系统的建议解决方案。

基于示例,我创建了一个Orchestrator 客户端( HelloOrchestratorClient.cs),它响应HttpTrigger. 此客户端从原始请求中提取一些信息,然后继续触发Orchestrator 函数( HelloOrchestrator.cs),传入一些提取的信息:

复杂的 HelloOrchestratorClient.cs:

[FunctionName("HttpSyncStart")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, methods: "get", Route = "orchestrators/{functionName}/wait")]
    HttpRequestMessage req,
    [OrchestrationClient] DurableOrchestrationClient starter,
    string functionName,
    ILogger log)
{       
    HttpReq originalRequest = new HttpReq() {
            DeveloperId = GetDevKey(req,apiHeaderKey),
            QueryString = req.RequestUri.Query,
            APIName = GetQueryStringValue(req,APIName),
            APIVersion = GetQueryStringValue(req,APIVersion)

    };
    string instanceId =   await starter.StartNewAsync(functionName, originalRequest);

    TimeSpan timeout = GetTimeSpan(req, Timeout) ?? TimeSpan.FromSeconds(30);
    TimeSpan retryInterval = GetTimeSpan(req, RetryInterval) ?? TimeSpan.FromSeconds(1);

    return  await starter.WaitForCompletionOrCreateCheckStatusResponseAsync(
        req,
        instanceId,
        timeout,
        retryInterval);

}

现在HelloOrchestrator.cs只是调用我们的一个内部 API 并返回一个JsonProduct有效负载(简单的 POCO 描述,你猜对了,一个标题),使用ActivityTigger命名HelloOrchestrator.APICall来调用 API。

复杂的 HelloOrchestrator.cs:

  [FunctionName("E1_JsonProduct")]
        public static async Task<List<JsonProduct>> Run(
            [OrchestrationTrigger] DurableOrchestrationContextBase context,
            ILogger log)
        {
            List<JsonProduct> output = new List<JsonProduct>();
            HttpReq r = context.GetInput<HttpReq>();
            if(r != null)
            {
                if(r.DeveloperId == null)
                {
                    return output;
                }
                output.Add(await context.CallActivityAsync<JsonProduct>("E1_CallAPI",r));
                return output;
            }
            return output;
        } 

[FunctionName("E1_CallAPI")]
public async static Task<JsonProduct> APICall([ActivityTrigger] HttpReq req,
    ILogger log)
{

    JsonProduct products  = null;
    string u = $"{baseAddress}{req.APIVersion}/{req.APIName}{req.QueryString}";  

    var request = new HttpRequestMessage(HttpMethod.Get, u);
    request.Headers.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json")
    );
    request.Headers.Add("x-apikey",req.DeveloperId);
     log.LogInformation($"URL calling = '{request.RequestUri.AbsoluteUri}'.");
    HttpResponseMessage response = await client.SendAsync(request);
    // return await response.Content.ReadAsStringAsync();
    if(response.IsSuccessStatusCode)
    {
        var formatter = new JsonMediaTypeFormatter
        {
            SerializerSettings = HelloProj.CosmosDB.Models.Products.Converter.Settings
        };

        products = await response.Content.ReadAsAsync<JsonProduct>(new [] {formatter});
    }
    return products;
}

旁注:如果我可以让它工作,计划是将一堆进程扇出到不同的 API 并再次扇入并合并 JSON 有效负载并将其返回给发起者。

我遇到的问题

因此,当我List<JsonProduct>从 中返回时HelloOrchestrator.Run,我会收到NullReferenceException在此Gist(大堆栈跟踪)上找到的以下内容,并且我收到来自Orchestrator Client的500 响应

下面证明output返回的确实在运行时有一个对象:

输出的运行时屏幕抓取

可能是由于(再次在这里JsonProduct找到模型类)的复杂性吗?我问,因为当我将我的Orchestrator 函数换成更简单的模型结构时,我没有收到 500,而是收到了我的 JSON 有效负载。

此示例显示了Simple Orchestrator 函数 HelloOrchestrator.cs,返回一个简单的TestToDo.cs模型的要点)平面对象,该对象不会出错

简单的 HelloOrchestrator.cs:

   [FunctionName("E1_Todo")]
    public static async Task<TestToDo> RunToDo(
    [OrchestrationTrigger] DurableOrchestrationContextBase context,
        ILogger log)
    {
        HttpReq r = context.GetInput<HttpReq>();
        TestToDo todo = new TestToDo();
        if(r != null)
        {
            todo = await context.CallActivityAsync<TestToDo>("E1_CallAPITodo",r);
        }
        return todo;
    }

[FunctionName("E1_CallAPITodo")]
public async static Task<TestToDo> APITodoCall([ActivityTrigger] HttpReq req,
    ILogger log)
{

    var request = new HttpRequestMessage(HttpMethod.Get, "https://jsonplaceholder.typicode.com/todos/1");
    request.Headers.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json")
    );
     log.LogInformation($"URL calling = '{request.RequestUri.AbsoluteUri}'. for {req.QueryString}");
    HttpResponseMessage response = await client.SendAsync(request);
    return await response.Content.ReadAsAsync<TestToDo>();
} 

更多信息

如果你需要我的完整原型项目,你可以在这里找到它们:

当你运行它时,在 Postman 之类的东西中使用以下内容(在 F5 之后):

http://localhost:7071/api/orchestrators/E1_JsonProduct/wait?timeout=20&retryInterval=0.25&api=products&apiVersion=v1&filterByImprints=W%26N&N

当你运行它时,在 Postman 之类的东西中使用以下内容(在 F5 之后):

http://localhost:7071/api/orchestrators/E1_Todo/wait?timeout=20&retryInterval=0.25

4

1 回答 1

1

查看您发布的调用堆栈,这NullReferenceException似乎是DurableOrchestrationClient课堂上的一个错误。查看代码(您可以在此处找到)似乎有可能如果您使用的查询字符串无法正确解析,则可能会出现 null-ref。

您提到您正在使用以下 URL 进行测试:

http://localhost:7071/api/orchestrators/E1_JsonProduct/wait?timeout=20&retryInterval=0.25&api=products&apiVersion=v1&filterByImprints=W%26N&N

我想知道最后两个字符 ( &N) 是否是问题的根源。是否可以编码&或完全删除它以隔离问题?

无论哪种方式,如果您可以在此处记录问题,那就太好了:https ://github.com/Azure/azure-functions-durable-extension/issues

于 2018-10-11T01:26:14.587 回答