F# AWS lambda - 部分异步函数永远不会执行

F# AWS lambda - Parts of asynchronous function are never executed

我在 AWS Lambda 中有一个异步 F# 函数。但是,在测试它时,永远不会调用部分函数。该函数总是在 10 秒后终止,即使 aws-lambda-tools-defaults.json 文件将超时指定为 30 秒。

代码如下:

namespace MyProject

open FSharp.Data

type SecretsJson = JsonProvider<"./Resources/Secrets.json", RootName="Secret">

module ApiClient = 
    let testGet (secrets: SecretsJson.Secret) =
        async {      
            printfn "%s" "3. This is sometimes printed out and sometimes not."
            
            let! test = Http.AsyncRequestString("https://postman-echo.com/get?foo1=bar1&foo2=bar2")
            printfn "%s" "4. This is never printed."
            return ""
        }
namespace MyProject

open Amazon.Lambda.Core
open Amazon
open Amazon.S3
open Amazon.S3.Util
open System.IO
open Amazon.S3.Model
open Amazon.SecretsManager.Extensions.Caching

[<assembly: LambdaSerializer(typeof<Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer>)>]
()

type Function() =
member __.FunctionHandler (input: S3EventNotification) (_: ILambdaContext) : System.Threading.Tasks.Task<unit> =
        printfn "%s" "1. This gets printed always."
        
        async {        
            use client = new AmazonS3Client(RegionEndpoint.EUWest1)
            use secretsCache = new SecretsManagerCache()
            
            let! secretsString = secretsCache.GetSecretString "secretsKey" |> Async.AwaitTask
            printfn "%s" "2. Also this is always printed."

            let secrets = SecretsJson.Parse(secretsString)
            let! response = ApiClient.testGet secrets

            printfn "%s" "5. This is never printed."
        } |> Async.StartAsTask

我不明白这种行为。我认为 |> Async.StartAsTask 表达式将确保 Function.FunctionHandler 中的整个 async 块作为标准 C# Task<T> 执行。还是我必须将每个 Async<'a> 函数转换为 Task<T>?或者我的代码中是否存在其他我没有看到的错误?

异步代码不应该是问题的根源。我尝试了以下方法:

open System
open Amazon.Lambda.Core

open FSharp.Data

let loadStuff (context: ILambdaContext) (i:int) =
        async {        

            let! test = Http.AsyncRequestString("https://www.google.com")

            sprintf "i:%i Length: %i" i test.Length
            |> context.Logger.LogLine

        } 

type Functions() =

member __.Get (request: APIGatewayProxyRequest) (context: ILambdaContext) =

    async {        

            do! [1..10]
                |>Seq.map (Loader.loadStuff context)
                |>Async.Parallel
                |>Async.Ignore

            do! Async.Sleep(10000)

            do! [11..15]
                |>Seq.map (Loader.loadStuff context)
                |>Async.Parallel
                |>Async.Ignore


    } 
    |> Async.StartAsTask

这需要 12 秒并输出:

i:6 Length: 47974
i:3 Length: 47201
i:4 Length: 47200
i:8 Length: 47255
i:5 Length: 47183
i:1 Length: 47145
i:7 Length: 47203
i:9 Length: 47177
i:10 Length: 47202
i:2 Length: 47198
i:14 Length: 47201
i:12 Length: 47155
i:11 Length: 47250
i:13 Length: 47162
i:15 Length: 47130

考虑在您的代码中添加 try catch 块,并使用 context.Logger.Logline 代替 printfn。此外,如果您有很长的 运行 件作品,例如>30 秒。考虑将它们分解成更多功能,并可能与 serverless workflows.

之类的东西协调它们