Deadlock when accessing a log object with an asynchronous method is executed synchronously

The following code tries to do some work and retries if there is an error. There is also error feedback calling a function that logs the error on the console.

During execution, an error is logged in the console only once, and when the program is paused, the main thread is blocked in retryErrorForever, and the worker thread is blocked upon receipt log.

But why?

module Program

type MyLogger(loggerName: string) =
    member __.Warn fmt =
        Printf.kprintf (printfn "%s: %s" loggerName) fmt

let log = MyLogger("Logger")

let retryErrorForever errorCallback retryTimeout work =
    let rec loop () = async {
        let! result = work

        match result with
        | Error e ->
            errorCallback e
            do! Async.Sleep retryTimeout
            return! loop()
        | Ok x -> return Ok x
    }

    loop ()

let retryWorkUntilOk logError timeout (work: unit -> Result<string, string>) =
    let workflow = async {
        return work ()
    }

    let result =
        retryErrorForever logError timeout workflow
        |> Async.RunSynchronously

    match result with
    | Ok x -> x
    | Error e -> failwith <| sprintf "Cannot doWork: %s" e

let logError error =
    log.Warn "%s" error

let doWork work =
    retryWorkUntilOk logError 1000 work

let errorOnly () : Result<string, string> =
    Error "You have no power here"

let result = doWork errorOnly

[<EntryPoint>]
let main _ =
    printfn "%A" result
    0
+4
source share
1 answer

When launched interactively, this program does exactly what it should do: it prints "You have no power here" every second forever.

, : let result = ... , main , . . , , - , async. , .

, , main, . , result , main:

let result() = doWork errorOnly

[<EntryPoint>]
let main _ =
    printfn "%A" <| result()
    0
+5

Source: https://habr.com/ru/post/1690145/


All Articles