Skip to content
This repository was archived by the owner on Nov 20, 2020. It is now read-only.

Commit 3eb2fcf

Browse files
committed
Add support for executing inner Tasks
1 parent 84cdd70 commit 3eb2fcf

1 file changed

Lines changed: 22 additions & 5 deletions

File tree

src/CallPolly/Rules.fs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ type PolicyConfig =
2323

2424
type GovernorState = { circuitState : string option; bulkheadAvailable : int option; queueAvailable : int option }
2525

26+
[<NoComparison; NoEquality>]
27+
[<RequireQualifiedAccess>]
28+
type TaskOrAsync<'T> =
29+
| Task of (CancellationToken -> Task<'T>)
30+
| Async of (Async<'T>)
31+
2632
/// Translates a PolicyConfig's rules to a Polly IAsyncPolicy instance that gets held in the ActionPolicy
2733
type Governor(log: Serilog.ILogger, buildFailurePolicy: unit -> Polly.PolicyBuilder, serviceName: string, callName: string, policyName: string, config: PolicyConfig) =
2834
let logBreach sla interval = log |> Events.Log.cutoffSlaBreached (serviceName, callName, policyName) sla interval
@@ -123,11 +129,15 @@ type Governor(log: Serilog.ILogger, buildFailurePolicy: unit -> Polly.PolicyBuil
123129
Some () // Compiler gets too clever if we never return Some
124130

125131
/// Execute and/or log failures regarding invocation of a function with the relevant policy applied
126-
member __.Execute(inner : Async<'a>) : Async<'a> =
132+
member __.Execute(inner: TaskOrAsync<'a>) : Async<'a> =
127133
match asyncPolicy with
128134
| None ->
129135
log.Debug("Policy Execute Raw {service:l}-{call:l}", serviceName, callName)
130-
inner
136+
match inner with
137+
| TaskOrAsync.Async a -> a
138+
| TaskOrAsync.Task factory -> async {
139+
let! ct = Async.CancellationToken
140+
return! factory ct |> Async.AwaitTaskCorrect }
131141
| Some polly -> async {
132142
let mutable wasFull = false
133143
// NB This logging is on a best-effort basis - obviously the guard here has an implied race condition
@@ -164,7 +174,10 @@ type Governor(log: Serilog.ILogger, buildFailurePolicy: unit -> Polly.PolicyBuil
164174

165175
// sic - cancellation of the inner computation needs to be controlled by Polly's chain of handlers
166176
// for example, if a cutoff is configured, it's Polly that will be requesting the cancellation
167-
Async.StartAsTask(inner, cancellationToken=pollyCt)
177+
match inner with
178+
| TaskOrAsync.Async a -> Async.StartAsTask(a, cancellationToken=pollyCt)
179+
| TaskOrAsync.Task factory -> factory pollyCt
180+
168181
let execute = async {
169182
let! ct = Async.CancellationToken // Grab async cancellation token of this `Execute` call, so cancellation gets propagated into the Polly [wrap]
170183
log.Debug("Policy Execute Inner {service:l}-{call:l}", serviceName, callName)
@@ -222,9 +235,13 @@ type CallPolicy<'TConfig when 'TConfig: equality> (makeGoverner : CallConfig<'TC
222235
member __.Policy = cfg.policy
223236
member __.Config = cfg.config
224237

225-
/// Execute the call, apply the policy rules
238+
/// Execute an inner Async computation, applying the policy rules
226239
member __.Execute(inner : Async<'t>) =
227-
governor.Execute inner
240+
governor.Execute (TaskOrAsync.Async inner)
241+
242+
/// Execute an inner Task-Method, applying the policy rules
243+
member __.ExecuteTask<'T>(inner : CancellationToken -> Task<'T>) =
244+
governor.Execute (TaskOrAsync.Task inner)
228245

229246
/// Facilitates dumping for diagnostics
230247
member __.InternalState =

0 commit comments

Comments
 (0)