How to flatten the nested try-catch block in F# for the following code? I am using EF Core with F#. The nested is required because I need to Rollback the transaction if there are errors in saving or committing the transaction!
let createTenant (ctx: AppContext) (tenant: Db.Tenant) (firstUser: Db.User) =
async {
try
let! db = ctx.Aquire()
use! transaction = db.Database.BeginTransactionAsync(IsolationLevel.Serializable) |> Async.AwaitTask
db.Tenant.Add tenant |> ignore
db.User.Add firstUser |> ignore
let! result =
async {
try
let! _ = db.SaveChangesAsync() |> Async.AwaitTask
do! transaction.CommitAsync() |> Async.AwaitTask
return Ok tenant.Id
with
| _ ->
do! transaction.RollbackAsync() |> Async.AwaitTask
return Error "internal error"
}
ctx.Release()
return result
with
| _ -> return Error "internal error"
}
On a side note, is this the clean/idiomatic way to handle exceptions in F#? Is there a better way to do this?
try/catch
. IfSaveChangesAsync()
errors then the transaction will be rolled back anyway and you jump into the outertry/catch
. \$\endgroup\$SaveChangesAsync()
orCommitAsync()
method? \$\endgroup\$Task
class, it would be better to use Ply or TaskBuilder to avoid usage ofAsync.AwaitTask
which might be slow and gives better interop experience when your library is called from other languages \$\endgroup\$