У меня есть агент, который я создал для работы с базой данных в фоновом режиме. Реализация выглядит примерно так:
let myAgent = MailboxProcessor<AgentData>.Start(fun inbox ->
let rec loop =
async {
let! data = inbox.Receive()
use conn = new System.Data.SqlClient.SqlConnection("...")
data |> List.map (fun e -> // Some transforms)
|> List.sortBy (fun (_,_,t,_,_) -> t)
|> List.iter (fun (a,b,c,d,e) ->
try
... // Do the database work
with e -> Log.error "Yikes")
return! loop
}
loop)
С этим я обнаружил, что если бы это вызывалось несколько раз за какое-то время, я бы начал собирать объекты SqlConnection и не удаляться, и в итоге у меня закончились бы соединения в пуле соединений (у меня нет точные метрики о том, сколько "нескольких", но запуск набора тестов интеграции дважды подряд может привести к тому, что пул соединений будет работать сухим).
Если я изменил use
на a using
, тогда все будет правильно установлено, и у меня нет проблемы:
let myAgent = MailboxProcessor<AgentData>.Start(fun inbox ->
let rec loop =
async {
let! data = inbox.Receive()
using (new System.Data.SqlClient.SqlConnection("...")) <| fun conn ->
data |> List.map (fun e -> // Some transforms)
|> List.sortBy (fun (_,_,t,_,_) -> t)
|> List.iter (fun (a,b,c,d,e) ->
try
... // Do the database work
with e -> Log.error "Yikes")
return! loop
}
loop)
Похоже, что метод using
для AsyncBuilder неправильно вызвал его функцию finally по какой-то причине, но непонятно почему. Это связано с тем, как я написал свое рекурсивное выражение async или это какая-то непонятная ошибка? И предполагает ли это, что использование use
в других выражениях вычислений может привести к такому же поведению?