Это не ответ на ваш вопрос, но я думаю, что то, как вы комбинируете асинхронные последовательности с синхронным кодом, на самом деле не дает вам никаких преимуществ. Асинхронные последовательности полезны, если вы хотите написать код, который будет перебирать данные, поступающие из какого-либо асинхронного источника данных, без блокировки, но если вы просто преобразуете свою последовательность в список, то нет смысла использовать асинхронные последовательности.
Лучшим подходом, который мог бы фактически решить вашу проблему, было бы изменение функции listObjects
, чтобы она сама возвращала асинхронную последовательность. Затем вы можете использовать конструкцию use
внутри асинхронной последовательности, а вычислительное выражение должно позаботиться об удалении объекта только после полной итерации последовательности:
let listObjects bucketName prefix = asyncSeq {
try
use client = new AmazonS3Client(RegionEndpoint.USEast2)
let request =
new ListObjectsV2Request(BucketName = bucketName, MaxKeys = 1000, Prefix = prefix)
let rec getKeys() = asyncSeq {
let! response = client.ListObjectsV2Async(request) |> Async.AwaitTask
for entry in response.S3Objects do
yield entry.Key
if response.IsTruncated then yield! getKeys() }
yield! getKeys()
with
| :? AmazonS3Exception as s3ex ->
Log.Error("S3 error occurred. Exception: {0}", s3ex)
| ex ->
Log.Error("Exception: {0}\n{1}", ex.Message, ex) }
Если вам действительно нужно сделать вещи синхронными, вы можете затем вызвать AsyncSeq.toList
по результату функции:
listObjects "whatever" "prefix" |> AsyncSeq.toList
Тем не менее, я не уверен, что это действительно решит вашу проблему. Я думаю, что ваш код должен работать как есть, и я не совсем уверен, как поведение может быть вызвано ошибкой в асинхронных последовательностях. Поэтому я предполагаю, что в вашем коде есть что-то еще, что вызывает ошибку.
РЕДАКТИРОВАТЬ Я только что попытался воспроизвести это поведение без всех ссылок, которые требуются в вашем коде, поэтому я адаптировал его, чтобы просто перебирать списки и печатать при удалении объекта. Вот мой код:
let listObjects () =
try
use client = { new IDisposable with member x.Dispose() = printfn "bye" }
let rec getKeys n = asyncSeq {
let! nn = Async.Sleep(1)
for i in 0 .. 1 do yield i
if n <> 0 then yield! getKeys(n-1)
else printfn "completed" }
printfn "getting"
getKeys 5 |> AsyncSeq.toList
with
| ex ->
printfn "nop"
List.empty
listObjects ()
Это правильно делает - печатает «получение», «завершение», а затем «пока», поэтому, если я случайно не изменил что-то существенное, похоже, что asyncSeq
здесь все делает правильно.
Можете ли вы попробовать добавить похожие use
и printf
в ваш код, просто чтобы убедиться, что в вашем случае поведение такое же?