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.
之类的东西协调它们
我在 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.
之类的东西协调它们