-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathLazyTask.fs
36 lines (29 loc) · 1.6 KB
/
LazyTask.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
namespace Equinox.Core
/// Asynchronous Lazy<'T> used to gate a workflow to ensure at most once execution of a computation.
type
#if !EQUINOX_CORE
// NOT PUBLIC in Equinox library - used internally in the impl of CacheEntry
// PUBLIC in Equinox.Core (which also uses it in the impl of TaskCell)
internal
#endif
LazyTask<'T>(startTask: System.Func<Task<'T>>) =
// NOTE due to `Lazy<T>` semantics, failed attempts will cache any exception; TaskCell compensates for this by rolling over to a new instance
let workflow = lazy startTask.Invoke()
/// Synchronously peek at what's been previously computed (if it's not Empty, or the last attempt Faulted).
member _.TryCompleted() =
if not workflow.IsValueCreated then ValueNone else
let t = workflow.Value
if t.Status <> System.Threading.Tasks.TaskStatus.RanToCompletion then ValueNone
else ValueSome t.Result
/// Used to rule out values where the computation yielded an exception or the result has now expired
member _.TryAwaitValid() = task {
let t = workflow.Value
// Determines if the last attempt completed, but failed, or was cancelled (e.g. due to timeout); For TMI see https://stackoverflow.com/a/33946166/11635
if t.IsFaulted || t.IsCanceled then return ValueNone
else
let! res = t
return ValueSome res }
/// Await the outcome of the computation.
member _.Await() = workflow.Value
/// Singleton Empty value
static member val Empty = LazyTask(fun () -> Task.FromException<'T>(System.InvalidOperationException "Uninitialized LazyTask"))