{"cells":[{"cell_type":"markdown","metadata":{},"source":["# Async (Polyglot)"]},{"cell_type":"code","execution_count":1,"metadata":{"duration_ms":9623,"language":"fsharp"},"outputs":[],"source":["#!import ../../lib/fsharp/Notebooks.livemd"]},{"cell_type":"code","execution_count":2,"metadata":{"duration_ms":188,"language":"fsharp"},"outputs":[],"source":["#!import ../../lib/fsharp/Testing.livemd"]},{"cell_type":"code","execution_count":3,"metadata":{"duration_ms":60,"language":"fsharp"},"outputs":[],"source":["#!import ../../lib/fsharp/Common.fs"]},{"cell_type":"code","execution_count":4,"metadata":{"duration_ms":8,"language":"fsharp"},"outputs":[],"source":["#if !INTERACTIVE\n","open Lib\n","#endif"]},{"cell_type":"code","execution_count":5,"metadata":{"duration_ms":54,"language":"fsharp"},"outputs":[],"source":["open Common"]},{"cell_type":"markdown","metadata":{},"source":["## choice"]},{"cell_type":"code","execution_count":6,"metadata":{"duration_ms":29,"language":"fsharp"},"outputs":[],"source":["let inline choice asyncs = async {\n","    let e = Event<_> ()\n","    use cts = new System.Threading.CancellationTokenSource ()\n","    let fn =\n","        asyncs\n","        |> Seq.map (fun a -> async {\n","            let! x = a\n","            e.Trigger x\n","        })\n","        |> Async.Parallel\n","        |> Async.Ignore\n","    Async.Start (fn, cts.Token)\n","    let! result = Async.AwaitEvent e.Publish\n","    cts.Cancel ()\n","    return result\n","}"]},{"cell_type":"markdown","metadata":{},"source":["## map"]},{"cell_type":"code","execution_count":7,"metadata":{"duration_ms":16,"language":"fsharp"},"outputs":[],"source":["let inline map fn a = async {\n","    let! x = a\n","    return fn x\n","}"]},{"cell_type":"markdown","metadata":{},"source":["## runWithTimeoutChoiceAsync"]},{"cell_type":"code","execution_count":8,"metadata":{"duration_ms":46,"language":"fsharp"},"outputs":[],"source":["let inline runWithTimeoutChoiceAsync (timeout : int) fn =\n","    let _locals () = $\"timeout: {timeout} / {_locals ()}\"\n","\n","    let timeoutTask = async {\n","        do! Async.Sleep timeout\n","        trace Debug (fun () -> \"runWithTimeoutChoiceAsync\") _locals\n","        return None\n","    }\n","\n","    let task = async {\n","        try\n","            let! result = fn\n","            return Some result\n","        with\n","        | :? System.AggregateException as ex when\n","            ex.InnerExceptions\n","            |> Seq.exists (function :? System.Threading.Tasks.TaskCanceledException -> true | _ -> false)\n","            ->\n","            trace Warning\n","                (fun () -> \"runWithTimeoutChoiceAsync\")\n","                (fun () -> $\"ex: {ex |> SpiralSm.format_exception} / {_locals ()}\")\n","            return None\n","        | ex ->\n","            trace Critical\n","                (fun () -> \"runWithTimeoutChoiceAsync\")\n","                (fun () -> $\"ex: {ex |> SpiralSm.format_exception} / {_locals ()}\")\n","            return None\n","    }\n","\n","    [ timeoutTask; task ]\n","    |> choice"]},{"cell_type":"code","execution_count":9,"metadata":{"duration_ms":35,"language":"fsharp"},"outputs":[],"source":["let inline runWithTimeoutChoice timeout fn =\n","    fn\n","    |> runWithTimeoutChoiceAsync timeout\n","    |> Async.RunSynchronously"]},{"cell_type":"code","execution_count":10,"metadata":{"duration_ms":79,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["11:53:34 \u001B[94md\u001B[0m #1 runWithTimeoutChoiceAsync / timeout: 10\n","<null>"]}],"source":["///- --test\n","\n","Async.Sleep 120\n","|> runWithTimeoutChoice 10\n","|> _assertEqual None"]},{"cell_type":"code","execution_count":11,"metadata":{"duration_ms":77,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["Some ()"]}],"source":["///- --test\n","\n","Async.Sleep 10\n","|> runWithTimeoutChoice 60\n","|> _assertEqual (Some ())"]},{"cell_type":"code","execution_count":12,"metadata":{"duration_ms":52,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["11:53:34 \u001B[91mc\u001B[0m #2 runWithTimeoutChoiceAsync / ex: System.Exception: error / timeout: 60\n","<null>"]}],"source":["///- --test\n","\n","async {\n","    raise (exn \"error\")\n","}\n","|> runWithTimeoutChoice 60\n","|> _assertEqual None"]},{"cell_type":"markdown","metadata":{},"source":["## catch"]},{"cell_type":"code","execution_count":13,"metadata":{"duration_ms":19,"language":"fsharp"},"outputs":[],"source":["let inline catch a =\n","    a\n","    |> Async.Catch\n","    |> map (function\n","        | Choice1Of2 result -> Ok result\n","        | Choice2Of2 ex -> Error ex\n","    )"]},{"cell_type":"markdown","metadata":{},"source":["## runWithTimeoutAsync"]},{"cell_type":"code","execution_count":14,"metadata":{"duration_ms":33,"language":"fsharp"},"outputs":[],"source":["let inline runWithTimeoutAsync (timeout : int) fn = async {\n","    let _locals () = $\"timeout: {timeout} / {_locals ()}\"\n","    let! child = Async.StartChild (fn, timeout)\n","    return!\n","        child\n","        |> catch\n","        |> map (function\n","            | Ok result -> Some result\n","            | Error (:? System.TimeoutException as ex) ->\n","                trace Debug (fun () -> $\"Async.runWithTimeoutAsync\") _locals\n","                None\n","            | Error ex ->\n","                trace Critical (fun () -> $\"Async.runWithTimeoutAsync** / timeout: {timeout} / ex: %A{ex}\") _locals\n","                None\n","        )\n","}"]},{"cell_type":"code","execution_count":15,"metadata":{"duration_ms":26,"language":"fsharp"},"outputs":[],"source":["let inline runWithTimeout timeout fn =\n","    fn\n","    |> runWithTimeoutAsync timeout\n","    |> Async.RunSynchronously"]},{"cell_type":"code","execution_count":16,"metadata":{"duration_ms":75,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["11:53:35 \u001B[94md\u001B[0m #3 Async.runWithTimeoutAsync / timeout: 10\n","<null>"]}],"source":["///- --test\n","\n","Async.Sleep 60\n","|> runWithTimeout 10\n","|> _assertEqual None"]},{"cell_type":"code","execution_count":17,"metadata":{"duration_ms":46,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["Some ()"]}],"source":["///- --test\n","\n","Async.Sleep 10\n","|> runWithTimeout 60\n","|> _assertEqual (Some ())"]},{"cell_type":"code","execution_count":18,"metadata":{"duration_ms":47,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["11:53:35 \u001B[91mc\u001B[0m #4 Async.runWithTimeoutAsync** / timeout: 60 / ex: System.Exception: error\n","   at FSI_0117.it@48935-117.Invoke(Unit unitVar) in input.fsx:line 4\n","   at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](AsyncActivation`1 ctxt, TResult result1, FSharpFunc`2 part2) in /__w/1/s/src/fsharp/src/FSharp.Core/async.fs:line 510\n","   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in /__w/1/s/src/fsharp/src/FSharp.Core/async.fs:line 113\n","--- End of stack trace from previous location ---\n","   at Microsoft.FSharp.Control.AsyncResult`1.Commit() in /__w/1/s/src/fsharp/src/FSharp.Core/async.fs:line 454\n","   at <StartupCode$FSharp-Core>.$Async.AwaitAndBindChildResult@1983-4.Invoke(Unit unitVar) in /__w/1/s/src/fsharp/src/FSharp.Core/async.fs:line 1985\n","   at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](AsyncActivation`1 ctxt, TResult result1, FSharpFunc`2 part2) in /__w/1/s/src/fsharp/src/FSharp.Core/async.fs:line 510\n","   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in /__w/1/s/src/fsharp/src/FSharp.Core/async.fs:line 113 / timeout: 60\n","<null>"]}],"source":["///- --test\n","\n","async {\n","    raise (exn \"error\")\n","}\n","|> runWithTimeout 60\n","|> _assertEqual None"]},{"cell_type":"markdown","metadata":{},"source":["## runWithTimeoutStrict"]},{"cell_type":"code","execution_count":19,"metadata":{"duration_ms":61,"language":"fsharp"},"outputs":[],"source":["let inline runWithTimeoutStrict (timeout : int) fn =\n","    let _locals () = $\"timeout: {timeout} / {_locals ()}\"\n","\n","    let timeoutTask = async {\n","        do! Async.Sleep timeout\n","        return None, _locals\n","    }\n","\n","    let task = async {\n","        try\n","            return Async.RunSynchronously (fn, timeout) |> Some, _locals\n","        with\n","        | :? System.TimeoutException as ex ->\n","            let _locals () = $\"ex: {ex |> SpiralSm.format_exception} / {_locals ()}\"\n","            return None, _locals\n","        | ex ->\n","            trace Critical\n","                (fun () -> \"Async.runWithTimeoutStrict / async error\")\n","                (fun () -> $\"ex: {ex |> SpiralSm.format_exception} / {_locals ()}\")\n","            return raise ex\n","    }\n","\n","    try\n","        [| timeoutTask; task |]\n","        |> Array.map Async.StartAsTask\n","        |> System.Threading.Tasks.Task.WhenAny\n","        |> fun task ->\n","            match task.Result.Result with\n","            | None, _locals ->\n","                trace Debug (fun () -> \"runWithTimeoutStrict\") _locals\n","                None\n","            | result, _ -> result\n","    with\n","    | :? System.AggregateException as ex when\n","        ex.InnerExceptions\n","        |> Seq.exists (function :? System.Threading.Tasks.TaskCanceledException -> true | _ -> false)\n","        ->\n","        trace Warning\n","            (fun () -> \"Async.runWithTimeoutStrict\")\n","            (fun () -> $\"ex: {ex |> SpiralSm.format_exception} / {_locals ()}\")\n","        None\n","    | ex ->\n","        trace Critical\n","            (fun () -> \"Async.runWithTimeoutStrict / task error\")\n","            (fun () -> $\"ex: {ex |> SpiralSm.format_exception} / {_locals ()}\")\n","        None"]},{"cell_type":"code","execution_count":20,"metadata":{"duration_ms":59,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["11:53:35 \u001B[94md\u001B[0m #5 runWithTimeoutStrict / timeout: 10\n","<null>"]}],"source":["///- --test\n","\n","Async.Sleep 60\n","|> runWithTimeoutStrict 10\n","|> _assertEqual None"]},{"cell_type":"code","execution_count":21,"metadata":{"duration_ms":56,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["Some ()"]}],"source":["///- --test\n","\n","Async.Sleep 10\n","|> runWithTimeoutStrict 60\n","|> _assertEqual (Some ())"]},{"cell_type":"code","execution_count":22,"metadata":{"duration_ms":50,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["11:53:35 \u001B[91mc\u001B[0m #6 Async.runWithTimeoutStrict / async error / ex: System.Exception: error / timeout: 60\n","11:53:35 \u001B[91mc\u001B[0m #7 Async.runWithTimeoutStrict / task error / ex: System.AggregateException: One or more errors occurred. (error) / timeout: 60\n","<null>"]}],"source":["///- --test\n","\n","async {\n","    raise (exn \"error\")\n","}\n","|> runWithTimeoutStrict 60\n","|> _assertEqual None"]},{"cell_type":"markdown","metadata":{},"source":["## awaitValueTask"]},{"cell_type":"code","execution_count":23,"metadata":{"duration_ms":17,"language":"fsharp"},"outputs":[],"source":["let inline awaitValueTaskUnit (task : System.Threading.Tasks.ValueTask) =\n","    task.AsTask () |> Async.AwaitTask\n","\n","let inline awaitValueTask (task : System.Threading.Tasks.ValueTask<_>) =\n","    task.AsTask () |> Async.AwaitTask"]},{"cell_type":"markdown","metadata":{},"source":["## init"]},{"cell_type":"code","execution_count":24,"metadata":{"duration_ms":15,"language":"fsharp"},"outputs":[],"source":["let inline init x = async {\n","    return x\n","}"]},{"cell_type":"code","execution_count":25,"metadata":{"duration_ms":23,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["1"]}],"source":["///- --test\n","\n","init 1\n","|> Async.RunSynchronously\n","|> _assertEqual 1"]},{"cell_type":"markdown","metadata":{},"source":["## withCancellationToken"]},{"cell_type":"code","execution_count":26,"metadata":{"duration_ms":15,"language":"fsharp"},"outputs":[],"source":["let inline withCancellationToken (ct : System.Threading.CancellationToken) fn =\n","    Async.StartImmediateAsTask (fn, ct)\n","    |> Async.AwaitTask"]},{"cell_type":"code","execution_count":27,"metadata":{"duration_ms":108,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["Error \"A task was canceled.\""]}],"source":["///- --test\n","\n","let cts = new System.Threading.CancellationTokenSource ()\n","\n","async {\n","    let run = async {\n","        do! Async.Sleep 100\n","        return 1\n","    }\n","\n","    let! child =\n","        run\n","        |> withCancellationToken cts.Token\n","        |> catch\n","        |> Async.StartChild\n","\n","    do! Async.Sleep 50\n","    cts.Cancel ()\n","    return! child\n","}\n","|> Async.RunSynchronously\n","|> Result.mapError _.Message\n","|> _assertEqual (Error (\"A task was canceled.\"))"]},{"cell_type":"markdown","metadata":{},"source":["## retryAsync"]},{"cell_type":"code","execution_count":28,"metadata":{"duration_ms":38,"language":"fsharp"},"outputs":[],"source":["let inline retryAsync retries fn =\n","    let rec 루프 retry lastError = async {\n","        try\n","            return!\n","                if retry <= retries\n","                then fn |> map Ok\n","                else lastError |> Error |> init\n","        with ex ->\n","            trace Debug (fun () -> $\"Async.retryAsync / retry: {retry}/{retries} / ex: {ex |> SpiralSm.format_exception}\") _locals\n","            do! Async.Sleep 30\n","            return! 루프 (retry + 1) (ex |> SpiralSm.format_exception)\n","    }\n","    루프 1 \"Async.retryAsync / invalid retries / retries: {retries}\""]},{"cell_type":"code","execution_count":29,"metadata":{"duration_ms":40,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["Ok 1"]}],"source":["///- --test\n","\n","let retry_fn_test = ref 0\n","async {\n","    retry_fn_test.Value <- retry_fn_test.Value + 1\n","    return retry_fn_test.Value\n","}\n","|> retryAsync 3\n","|> Async.RunSynchronously\n","|> _assertEqual (Ok 1)"]},{"cell_type":"code","execution_count":30,"metadata":{"duration_ms":105,"language":"fsharp"},"outputs":[{"name":"stdout","output_type":"stream","text":["11:53:35 \u001B[94md\u001B[0m #8 Async.retryAsync / retry: 1/3 / ex: System.Exception: test\n","11:53:35 \u001B[94md\u001B[0m #9 Async.retryAsync / retry: 2/3 / ex: System.Exception: test\n","Ok 2"]}],"source":["///- --test\n","\n","let retry_fn_test = ref 0\n","async {\n","    return\n","        if retry_fn_test.Value >= 2\n","        then retry_fn_test.Value\n","        else\n","            retry_fn_test.Value <- retry_fn_test.Value + 1\n","            failwith \"test\"\n","}\n","|> retryAsync 3\n","|> Async.RunSynchronously\n","|> _assertEqual (Ok 2)"]},{"cell_type":"markdown","metadata":{},"source":["## fold"]},{"cell_type":"code","execution_count":31,"metadata":{"duration_ms":32,"language":"fsharp"},"outputs":[],"source":["let fold folder state array =\n","    let rec 루프 acc i =\n","        async {\n","            if i < Array.length array then\n","                let! newAcc = folder acc array.[i]\n","                return! 루프 newAcc (i + 1)\n","            else\n","                return acc\n","        }\n","    루프 state 0"]}],"metadata":{"kernelspec":{"display_name":"Spiral","language":"spiral","name":"spiral"}},"nbformat":4,"nbformat_minor":5}