Skip to content

Commit

Permalink
chore: LangVersion 8 (#442)
Browse files Browse the repository at this point in the history
  • Loading branch information
bartelink authored Jan 18, 2024
1 parent 36bec9b commit 5b38e2f
Show file tree
Hide file tree
Showing 27 changed files with 54 additions and 59 deletions.
1 change: 1 addition & 0 deletions Equinox.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nullary/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=recomputation/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=resync/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Resyncing/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Resyncs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=roundtripping/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=roundtrips/@EntryIndexedValue">True</s:Boolean>
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "6.0.300",
"version": "8.0.100",
"rollForward": "latestMajor"
}
}
4 changes: 2 additions & 2 deletions samples/Store/Domain.Tests/SavedForLaterTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ let ``Event aggregation should carry set semantics`` (commands: Command list) =
match event with
| Events.Added appended -> state.UnionWith appended.skus
| Events.Removed removed -> state.ExceptWith removed.skus
| Events.Merged merged -> state.UnionWith (merged.items |> Seq.map (fun s -> s.skuId))
| Events.Merged merged -> state.UnionWith(merged.items |> Seq.map _.skuId)
| Events.Compacted compacted ->
state.Clear()
state.UnionWith (compacted.items |> Seq.map (fun s -> s.skuId))
state.UnionWith(compacted.items |> Seq.map _.skuId)
state

let state',events = run commands
Expand Down
4 changes: 2 additions & 2 deletions samples/Store/Domain/Cart.fs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ module Fold =
module Snapshot =

let generate (s: State) =
Events.Snapshotted <|
{ items = [| for i in s.items -> { skuId = i.skuId; quantity = i.quantity; returnsWaived = i.returnsWaived } |] }
Events.Snapshotted
{ items = [| for i in s.items -> { skuId = i.skuId; quantity = i.quantity; returnsWaived = i.returnsWaived } |] }
let isOrigin = function Events.Snapshotted _ -> true | _ -> false
let config = isOrigin, generate
let hydrate (s: Events.Compaction.State): State =
Expand Down
4 changes: 2 additions & 2 deletions samples/Store/Domain/ContactPreferences.fs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ type Service internal (resolve: ClientId -> Equinox.Decider<Events.Event, Fold.S

member _.ReadVersion(clientId) =
let decider = resolve clientId
decider.QueryEx(fun x -> x.Version)
decider.QueryEx _.Version

member _.ReadStale(clientId) =
member _.ReadAnyCachedValue(clientId) =
let decider = resolve clientId
decider.Query(id, Equinox.LoadOption.AnyCachedValue)

Expand Down
8 changes: 4 additions & 4 deletions samples/Store/Domain/Favorites.fs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module Fold =

type private InternalState(input: State) =
let dict = System.Collections.Generic.Dictionary<SkuId, Events.Favorited>()
let favorite (e: Events.Favorited) = dict.[e.skuId] <- e
let favorite (e: Events.Favorited) = dict[e.skuId] <- e
let favoriteAll (xs: Events.Favorited seq) = for x in xs do favorite x
do favoriteAll input
member _.ReplaceAllWith xs = dict.Clear(); favoriteAll xs
Expand All @@ -53,7 +53,7 @@ let has skuId (state: Fold.State) = state |> Array.exists (fun x -> x.skuId = sk

let decideFavorite date skuIds state = [|
for skuId in Seq.distinct skuIds do
if state |> has skuId |> not then
if not (state |> has skuId) then
Events.Favorited { date = date; skuId = skuId } |]

let decideUnfavorite skuId state = [|
Expand All @@ -76,10 +76,10 @@ type Service internal (resolve: ClientId -> Equinox.Decider<Events.Event, Fold.S

member _.ListWithVersion clientId: Async<int64 * Events.Favorited []> =
let decider = resolve clientId
decider.QueryEx(fun ctx -> ctx.Version, ctx.State)
decider.QueryEx(fun c -> c.Version, c.State)

// NOTE not a real world example - used for an integration test; TODO get a better example where it's actually relevant
member _.UnfavoriteWithPostVersion(clientId, sku) =
member _.UnfavoriteWithPostVersion(clientId, sku): Async<int64> =
let decider = resolve clientId
decider.TransactEx((fun c -> decideUnfavorite sku c.State), render = _.Version)

Expand Down
4 changes: 2 additions & 2 deletions samples/Store/Domain/SavedForLater.fs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ type Service internal (resolve: ClientId -> Equinox.Decider<Events.Event, Fold.S

member _.Remove(clientId, resolveSkus: (SkuId -> bool) -> Async<SkuId[]>): Async<unit> =
let decider = resolve clientId
decider.Transact(fun state-> async {
let contents = state |> Seq.map (fun i -> i.skuId) |> set
decider.Transact(fun state -> async {
let contents = state |> Seq.map _.skuId |> set
let! skusToRemove = resolveSkus contents.Contains
return (), decide maxSavedItems (Remove skusToRemove) state |> snd })

Expand Down
2 changes: 1 addition & 1 deletion samples/Store/Integration/TestOutput.fs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ type TestOutput(testOutput: Xunit.Abstractions.ITestOutputHelper) =
.WriteTo.Sink(testOutputAndTrace)
.WriteTo.Seq("http://localhost:5341")
|> fun c -> match sink with Some s -> c.WriteTo.Sink(s) | None -> c
|> fun c -> c.CreateLogger()
|> _.CreateLogger()
3 changes: 1 addition & 2 deletions samples/Tutorial/AsAt.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@
// - the same general point applies to over-using querying of streams for read purposes as we do here;
// applying CQRS principles can often lead to a better model regardless of raw necessity

#if !LOCAL
#if LOCAL
// Compile Tutorial.fsproj by either a) right-clicking or b) typing
// dotnet build samples/Tutorial before attempting to send this to FSI with Alt-Enter
#I "bin/Debug/net6.0/"
#r "System.Runtime.Caching.dll"
#r "Serilog.dll"
#r "Serilog.Sinks.Console.dll"
#r "Serilog.Sinks.Seq.dll"
#r "Newtonsoft.Json.dll"
#r "FSharp.UMX.dll"
#r "FsCodec.dll"
#r "Equinox.dll"
Expand Down
3 changes: 1 addition & 2 deletions samples/Tutorial/Cosmos.fsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
#if !LOCAL
#if LOCAL
// Compile Tutorial.fsproj by either a) right-clicking or b) typing
// dotnet build samples/Tutorial before attempting to send this to FSI with Alt-Enter
#I "bin/Debug/net6.0/"
#r "System.Net.Http"
#r "System.Runtime.Caching.dll"
#r "Serilog.dll"
#r "Serilog.Sinks.Console.dll"
#r "Newtonsoft.Json.dll"
#r "TypeShape.dll"
#r "Equinox.dll"
#r "FSharp.UMX.dll"
Expand Down
4 changes: 2 additions & 2 deletions samples/Tutorial/Counter.fsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !LOCAL
#if LOCAL
// Compile Tutorial.fsproj before attempting to send this to FSI with Alt-Enter by either:
// a) right-clicking or
// b) typing dotnet build samples/Tutorial
Expand All @@ -13,7 +13,7 @@
#r "FsCodec.Box.dll"
#else
#r "nuget:Equinox.MemoryStore, *-*"
#r "nuget:FsCodec.Box"
#r "nuget:FsCodec.Box, *-*"
#r "nuget:Serilog.Sinks.Console"
#endif

Expand Down
2 changes: 1 addition & 1 deletion samples/Tutorial/Favorites.fsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !LOCAL
#if LOCAL
// Compile Tutorial.fsproj by either a) right-clicking or b) typing
// dotnet build samples/Tutorial before attempting to send this to FSI with Alt-Enter
#I "bin/Debug/net6.0/"
Expand Down
14 changes: 6 additions & 8 deletions samples/Tutorial/FulfilmentCenter.fsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#if !LOCAL
#if LOCAL
#I "bin/Debug/net6.0/"
#r "System.Net.Http"
#r "System.Runtime.Caching.dll"
#r "Serilog.dll"
#r "Serilog.Sinks.Console.dll"
#r "Newtonsoft.Json.dll"
#r "Equinox.dll"
#r "FSharp.UMX.dll"
#r "FsCodec.dll"
Expand All @@ -16,7 +15,6 @@
#else
#r "nuget:Equinox.MemoryStore, *-*"
#r "nuget:Equinox.CosmosStore, *-*"
#r "nuget:FsCodec.NewtonsoftJson, *-*"
#r "nuget:FsCodec.SystemTextJson, *-*"
#r "nuget:Serilog.Sinks.Console"
#r "nuget:Serilog.Sinks.Seq"
Expand Down Expand Up @@ -44,8 +42,8 @@ module Types =
state : string
zip : string
isBusiness : bool option
isWeekendDeliveries : bool option
businessName : string option }
isWeekendDeliveries : bool option
businessName : string option }
type Summary = { name : FcName option; address : Address option; contact : ContactInformation option; details : FcDetails option }

module FulfilmentCenter =
Expand Down Expand Up @@ -107,10 +105,10 @@ module FulfilmentCenter =
member _.UpdateDetails(fc, value) =
let decider = resolve fc
decider.Transact(Decisions.updateDetails value)
member _.Read fc : Async<Summary> =
member _.Read fc: Async<Summary> =
let decider = resolve fc
decider.Query id
member _.QueryWithVersion(fc, render : Fold.State -> 'res) : Async<int64*'res> =
member _.QueryWithVersion(fc, render: Fold.State -> 'res): Async<int64*'res> =
let decider = resolve fc
decider.QueryEx(fun c -> c.Version, render c.State)

Expand Down Expand Up @@ -184,4 +182,4 @@ module FulfilmentCenterSummary =
decider.Transact(decideIngest version value)
member _.TryRead id: Async<Summary option> =
let decider = resolve id
decider.Query(Option.map (fun s -> s.state))
decider.Query(Option.map _.state)
4 changes: 2 additions & 2 deletions samples/Tutorial/Gapless.fs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ module Fold =
{ reserved = state.reserved; confirmed = Set.empty; released = Set.empty; next = state.next }
let fold (state: State) (xs: Events.Event[]): State =
let s = State.toInternal state
let state' = (s, xs) ||> Array.fold (fun s -> s.Evolve)
let state' = (s, xs) ||> Array.fold _.Evolve
state'.ToState()

let decideReserve count (state : Fold.State) : int64[] * Events.Event[] =
let decideReserve count (state : Fold.State): int64[] * Events.Event[] =
failwith "TODO"

let decideConfirm item (state : Fold.State) : Events.Event[] =
Expand Down
3 changes: 1 addition & 2 deletions samples/Tutorial/Todo.fsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#if !LOCAL
#if LOCAL
// Compile Tutorial.fsproj by either a) right-clicking or b) typing
// dotnet build samples/Tutorial before attempting to send this to FSI with Alt-Enter
#I "bin/Debug/net6.0/"
#r "System.Runtime.Caching.dll"
#r "Serilog.dll"
#r "Serilog.Sinks.Console.dll"
#r "Newtonsoft.Json.dll"
#r "TypeShape.dll"
#r "Equinox.dll"
#r "FSharp.UMX.dll"
Expand Down
10 changes: 5 additions & 5 deletions src/Equinox.CosmosStore/CosmosStore.fs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ module Log =
// Yes, there's a minor race here between the use of the values and the reset
let duration = Stats.LogSink.Restart()
if rows > 1 then logActivity "TOTAL" totalCount (totalRRu + totalWRu) totalMs
let measures: (string * (TimeSpan -> float)) list = [ "s", fun x -> x.TotalSeconds(*; "m", fun x -> x.TotalMinutes; "h", fun x -> x.TotalHours*) ]
let measures: (string * (TimeSpan -> float)) list = [ "s", _.TotalSeconds(*; "m", _.TotalMinutes; "h", _.TotalHours*) ]
let logPeriodicRate name count rru wru = log.Information("{rru:n1}R/{wru:n1}W CU @ {count:n0} rp{unit}", rru, wru, count, name)
for uom, f in measures do let d = f duration in if d <> 0. then logPeriodicRate uom (float totalCount/d |> int64) (totalRRu/d) (totalWRu/d)

Expand Down Expand Up @@ -630,7 +630,7 @@ module internal Tip =
| ReadResult.NotModified -> return Result.NotModified
| ReadResult.NotFound -> return Result.NotFound
| ReadResult.Found tip ->
let minIndex = maybePos |> Option.map (fun x -> x.index)
let minIndex = maybePos |> Option.map _.index
return Result.Found (Position.fromEtagAndIndex (tip._etag, tip.n), tip.i, Enum.EventsAndUnfolds(tip, ?maxIndex = maxIndex, ?minIndex = minIndex) |> Array.ofSeq) }
let tryFindOrigin (tryDecode: ITimelineEvent<EventBody> -> 'event voption, isOrigin: 'event -> bool) xs =
let stack = ResizeArray()
Expand Down Expand Up @@ -917,7 +917,7 @@ module Prune =
container.GetItemQueryIterator<_>("SELECT c.id, c.i, c.n FROM c ORDER by c.i", requestOptions = qro)
let mapPage i (t: StopwatchInterval) (page: FeedResponse<BatchIndices>) =
let batches, rc, ms = Array.ofSeq page, page.RequestCharge, t.ElapsedMilliseconds
let next = Array.tryLast batches |> Option.map (fun x -> x.n)
let next = Array.tryLast batches |> Option.map _.n
let reqMetric: Log.Measurement = { database = container.Database.Id; container = container.Id; stream = stream; interval = t; bytes = -1; count = batches.Length; ru = rc }
let log = let evt = Log.Metric.PruneResponse reqMetric in log |> Log.prop "batchIndex" i |> Log.event evt
log.Information("EqxCosmos {action:l} {batches} {ms:f1}ms n={next} {ru}RU", "PruneResponse", batches.Length, ms, Option.toNullable next, rc)
Expand All @@ -928,7 +928,7 @@ module Prune =
let handle (batches: BatchIndices[], rc) = task {
let mutable delCharges, batchesDeleted, trimCharges, batchesTrimmed, eventsDeleted, eventsDeferred = 0., 0, 0., 0, 0, 0
let mutable lwm = None
for x in batches |> Seq.takeWhile (fun x -> isRelevant x || lwm = None) do
for x in batches |> Seq.takeWhile (fun x -> isRelevant x || Option.isNone lwm) do
let batchSize = x.n - x.i |> int
let eligibleEvents = max 0 (min batchSize (int (indexInclusive + 1L - x.i)))
if isTip x then // Even if we remove the last event from the Tip, we need to retain a) unfolds b) position (n)
Expand Down Expand Up @@ -1410,7 +1410,7 @@ type EventsContext
return pos', data }

let getRange direction startPos =
let startPos = startPos |> Option.map (fun x -> x.index)
let startPos = startPos |> Option.map _.index
match direction with
| Direction.Forward -> startPos, None
| Direction.Backward -> None, startPos
Expand Down
10 changes: 5 additions & 5 deletions src/Equinox.DynamoStore/DynamoStore.fs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ module Batch =
let (d, D), (m, M) = InternalBody.toStreamAndEncoding x.d, InternalBody.toStreamAndEncoding x.m
{ t = x.t; d = d; D = D; m = m; M = M; x = x.correlationId; y = x.causationId }
let eventsToSchema (xs: Event[]): (*case*) string[] * EventSchema[] =
xs |> Array.map (fun x -> x.c), xs |> Array.map toEventSchema
xs |> Array.map _.c, xs |> Array.map toEventSchema
let private toUnfoldSchema (x: Unfold): UnfoldSchema =
let (d, D), (m, M) = InternalBody.toStreamAndEncoding x.d, InternalBody.toStreamAndEncoding x.m
{ i = x.i; t = x.t; c = x.c; d = d; D = D; m = m; M = M }
Expand Down Expand Up @@ -366,7 +366,7 @@ module Log =
rows <- rows + 1
| _ -> ()
if rows > 1 then logActivity "TOTAL" totalCount (totalRRu + totalWRu) totalMs
let measures: (string * (TimeSpan -> float)) list = [ "s", fun x -> x.TotalSeconds(*; "m", fun x -> x.TotalMinutes; "h", fun x -> x.TotalHours*) ]
let measures: (string * (TimeSpan -> float)) list = [ "s", _.TotalSeconds(*; "m", _.TotalMinutes; "h", _.TotalHours*) ]
let logPeriodicRate name count rru wru = log.Information("{table} {rru:n1}R/{wru:n1}W CU @ {count:n0} rp{unit}", table, rru, wru, count, name)
for uom, f in measures do let d = f res.Elapsed in if d <> 0. then logPeriodicRate uom (float totalCount/d |> int64) (totalRRu/d) (totalWRu/d)

Expand Down Expand Up @@ -671,7 +671,7 @@ module internal Tip =
| Res.NotModified -> return Res.NotModified
| Res.NotFound -> return Res.NotFound
| Res.Found tip ->
let minIndex = maybePos |> Option.map (fun x -> x.index)
let minIndex = maybePos |> Option.map _.index
return Res.Found (Position.fromTip tip, Batch.baseIndex tip, tip |> enumEventsAndUnfolds (minIndex, maxIndex)) }

module internal Query =
Expand Down Expand Up @@ -921,7 +921,7 @@ module internal Prune =
// need to sort by n to guarantee we don't ever leave an observable gap in the sequence
let query ct = table.QueryIAndNOrderByNAscending(stream, maxItems, ct)
let mapPage (i, t: StopwatchInterval, batches: BatchIndices[], rc) =
let next = Array.tryLast batches |> Option.map (fun x -> x.n)
let next = Array.tryLast batches |> Option.map _.n
let reqMetric = Log.metric table.Name stream t -1 batches.Length rc
let log = let evt = Log.Metric.PruneResponse reqMetric in log |> Log.prop "batchIndex" i |> Log.event evt
log.Information("EqxDynamo {action:l} {batches} {ms:f1}ms n={next} {ru}RU",
Expand All @@ -932,7 +932,7 @@ module internal Prune =
let handle (batches: BatchIndices[], rc) = task {
let mutable delCharges, batchesDeleted, trimCharges, batchesTrimmed, eventsDeleted, eventsDeferred = 0., 0, 0., 0, 0, 0
let mutable lwm = None
for x in batches |> Seq.takeWhile (fun x -> isRelevant x || lwm = None) do
for x in batches |> Seq.takeWhile (fun x -> isRelevant x || Option.isNone lwm) do
let batchSize = x.n - x.index |> int
let eligibleEvents = max 0 (min batchSize (int (indexInclusive + 1L - x.index)))
if x.isTip then // Even if we remove the last event from the Tip, we need to retain a) unfolds b) position (n)
Expand Down
8 changes: 4 additions & 4 deletions src/Equinox.EventStore/EventStore.fs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ module Log =
// Yes, there's a minor race here between the use of the values and the reset
let duration = Stats.LogSink.Restart()
if rows > 1 then logActivity "TOTAL" totalCount totalMs
let measures: (string * (TimeSpan -> float)) list = [ "s", fun x -> x.TotalSeconds(*; "m", fun x -> x.TotalMinutes; "h", fun x -> x.TotalHours*) ]
let measures: (string * (TimeSpan -> float)) list = [ "s", _.TotalSeconds(*; "m", _.TotalMinutes; "h", _.TotalHours*) ]
let logPeriodicRate name count = log.Information("rp{name} {count:n0}", name, count)
for uom, f in measures do let d = f duration in if d <> 0. then logPeriodicRate uom (float totalCount/d |> int64)

Expand Down Expand Up @@ -539,12 +539,12 @@ module private Discovery =
let buildDns np (f: DnsClusterSettingsBuilder -> DnsClusterSettingsBuilder) =
ClusterSettings.Create().DiscoverClusterViaDns().KeepDiscovering()
|> fun s -> match np with NodePreference.Random -> s.PreferRandomNode() | NodePreference.PreferSlave -> s.PreferFollowerNode() | _ -> s
|> f |> fun s -> s.Build()
|> f |> _.Build()

let buildSeeded np (f: GossipSeedClusterSettingsBuilder -> GossipSeedClusterSettingsBuilder) =
ClusterSettings.Create().DiscoverClusterViaGossipSeeds().KeepDiscovering()
|> fun s -> match np with NodePreference.Random -> s.PreferRandomNode() | NodePreference.PreferSlave -> s.PreferFollowerNode() | _ -> s
|> f |> fun s -> s.Build()
|> f |> _.Build()

let configureDns clusterDns maybeManagerPort (x: DnsClusterSettingsBuilder) =
x.SetClusterDns(clusterDns)
Expand Down Expand Up @@ -599,7 +599,7 @@ type EventStoreConnector
|> fun s -> match clientConnectionTimeout with Some v -> s.WithConnectionTimeoutOf v | None -> s // default: 1000 ms
|> fun s -> match log with Some log -> log.Configure s | None -> s
|> fun s -> match custom with Some c -> c s | None -> s
|> fun s -> s.Build()
|> _.Build()

/// Yields an IEventStoreConnection configured and Connect()ed to a node (or the cluster) per the supplied `discovery` and `clusterNodePreference` preference
member _.Connect
Expand Down
2 changes: 1 addition & 1 deletion src/Equinox.EventStoreDb/Equinox.EventStoreDb.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<ItemGroup>
<PackageReference Include="MinVer" Version="4.2.0" PrivateAssets="All" />

<PackageReference Include="FSharp.Core" Version="6.0.7"><ExcludeAssets>contentfiles</ExcludeAssets></PackageReference>
<PackageReference Include="FSharp.Core" Version="6.0.7" ExcludeAssets="contentfiles" />
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="22.0.0" />
<PackageReference Include="FSharp.Control.TaskSeq" Version="0.4.0-alpha.1" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/Equinox.EventStoreDb/EventStoreDb.fs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ module Log =
// Yes, there's a minor race here between the use of the values and the reset
let duration = Stats.LogSink.Restart()
if rows > 1 then logActivity "TOTAL" totalCount totalMs
let measures: (string * (TimeSpan -> float)) list = [ "s", fun x -> x.TotalSeconds(*; "m", fun x -> x.TotalMinutes; "h", fun x -> x.TotalHours*) ]
let measures: (string * (TimeSpan -> float)) list = [ "s", _.TotalSeconds(*; "m", _.TotalMinutes; "h", _.TotalHours*) ]
let logPeriodicRate name count = log.Information("rp{name} {count:n0}", name, count)
for uom, f in measures do let d = f duration in if d <> 0. then logPeriodicRate uom (float totalCount/d |> int64)

Expand Down
Loading

0 comments on commit 5b38e2f

Please sign in to comment.