Skip to content

Commit

Permalink
refactor: Tidy Argu processing (#135)
Browse files Browse the repository at this point in the history
  • Loading branch information
bartelink authored Dec 14, 2023
1 parent b4474d6 commit 58e491b
Show file tree
Hide file tree
Showing 43 changed files with 342 additions and 403 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The `Unreleased` section name is replaced by the expected version of next releas
### Changed

- Target `Equinox` v `4.0.0-rc.14.5`, `Propulsion` v `3.0.0-rc.9.11`, `FsCodec` v `3.0.0-rc.14.1` [#131](https://github.com/jet/dotnet-templates/pull/131)
- Target `Argu` v `6.0.14` [#135](https://github.com/jet/dotnet-templates/pull/135)

### Removed

Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,9 @@ let main argv =
try let args = Args.parse EnvVar.tryGet argv
try Log.Logger <- LoggerConfiguration().Configure(verbose=args.Verbose).CreateLogger()
try run args |> Async.RunSynchronously; 0
with e when not (e :? MissingArg) -> Log.Fatal(e, "Exiting"); 2
with e when not (e :? System.Threading.Tasks.TaskCanceledException) -> Log.Fatal(e, "Exiting"); 2
finally Log.CloseAndFlush()
with MissingArg msg -> eprintfn "%s" msg; 1
| :? Argu.ArguParseException as e -> eprintfn "%s" e.Message; 1
with :? Argu.ArguParseException as e -> eprintfn "%s" e.Message; 1
| e -> eprintf "Exception %s" e.Message; 1
```

Expand Down
2 changes: 1 addition & 1 deletion equinox-shipping/Watchdog.Lambda/Function.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ open System
type Configuration(appName, ?tryGet) =
let envVarTryGet = Environment.GetEnvironmentVariable >> Option.ofObj
let tryGet = defaultArg tryGet envVarTryGet
let get key = match tryGet key with Some value -> value | None -> failwithf "Missing Argument/Environment Variable %s" key
let get key = match tryGet key with Some value -> value | None -> failwithf $"Missing Argument/Environment Variable %s{key}"

member _.DynamoRegion = tryGet Propulsion.DynamoStore.Lambda.Args.Dynamo.REGION
member _.DynamoServiceUrl = get Propulsion.DynamoStore.Lambda.Args.Dynamo.SERVICE_URL
Expand Down
39 changes: 18 additions & 21 deletions equinox-shipping/Watchdog/Args.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ module Args
open System
open FSharp.Control

exception MissingArg of message: string with override this.Message = this.message
let missingArg msg = raise (MissingArg msg)

let [<Literal>] REGION = "EQUINOX_DYNAMO_REGION"
let [<Literal>] SERVICE_URL = "EQUINOX_DYNAMO_SERVICE_URL"
let [<Literal>] ACCESS_KEY = "EQUINOX_DYNAMO_ACCESS_KEY_ID"
Expand All @@ -16,20 +13,20 @@ let [<Literal>] INDEX_TABLE = "EQUINOX_DYNAMO_TABLE_INDEX"

type Configuration(tryGet: string -> string option) =

let get key = match tryGet key with Some value -> value | None -> failwith $"Missing Argument/Environment Variable %s{key}"
member val tryGet = tryGet
member _.get key = match tryGet key with Some value -> value | None -> missingArg $"Missing Argument/Environment Variable %s{key}"

member x.CosmosConnection = x.get "EQUINOX_COSMOS_CONNECTION"
member x.CosmosDatabase = x.get "EQUINOX_COSMOS_DATABASE"
member x.CosmosContainer = x.get "EQUINOX_COSMOS_CONTAINER"
member _.CosmosConnection = get "EQUINOX_COSMOS_CONNECTION"
member _.CosmosDatabase = get "EQUINOX_COSMOS_DATABASE"
member _.CosmosContainer = get "EQUINOX_COSMOS_CONTAINER"

member x.DynamoServiceUrl = x.get SERVICE_URL
member x.DynamoAccessKey = x.get ACCESS_KEY
member x.DynamoSecretKey = x.get SECRET_KEY
member x.DynamoTable = x.get TABLE
member x.DynamoRegion = x.tryGet REGION
member _.DynamoServiceUrl = get SERVICE_URL
member _.DynamoAccessKey = get ACCESS_KEY
member _.DynamoSecretKey = get SECRET_KEY
member _.DynamoTable = get TABLE
member _.DynamoRegion = tryGet REGION

member x.EventStoreConnection = x.get "EQUINOX_ES_CONNECTION"
member _.EventStoreConnection = get "EQUINOX_ES_CONNECTION"
member _.MaybeEventStoreConnection = tryGet "EQUINOX_ES_CONNECTION"
member _.MaybeEventStoreCredentials = tryGet "EQUINOX_ES_CREDENTIALS"

Expand All @@ -50,7 +47,7 @@ module Cosmos =
| [<AltCommandLine "-rt">] RetriesWaitTime of float
interface IArgParserTemplate with
member p.Usage = p |> function
| Verbose _ -> "request verbose logging."
| Verbose -> "request verbose logging."
| ConnectionMode _ -> "override the connection mode. Default: Direct."
| Connection _ -> "specify a connection string for a Cosmos account. (optional if environment variable EQUINOX_COSMOS_CONNECTION specified)"
| Database _ -> "specify a database name for Cosmos store. (optional if environment variable EQUINOX_COSMOS_DATABASE specified)"
Expand All @@ -60,15 +57,15 @@ module Cosmos =
| RetriesWaitTime _ -> "specify max wait-time for retry when being throttled by Cosmos in seconds (default: 5)"

type Arguments(c: Configuration, p: ParseResults<Parameters>) =
let connection = p.TryGetResult Connection |> Option.defaultWith (fun () -> c.CosmosConnection)
let connection = p.GetResult(Connection, fun () -> c.CosmosConnection)
let discovery = Equinox.CosmosStore.Discovery.ConnectionString connection
let mode = p.TryGetResult ConnectionMode
let timeout = p.GetResult(Timeout, 5.) |> TimeSpan.FromSeconds
let retries = p.GetResult(Retries, 1)
let maxRetryWaitTime = p.GetResult(RetriesWaitTime, 5.) |> TimeSpan.FromSeconds
let connector = Equinox.CosmosStore.CosmosStoreConnector(discovery, timeout, retries, maxRetryWaitTime, ?mode = mode)
let database = p.TryGetResult Database |> Option.defaultWith (fun () -> c.CosmosDatabase)
let container = p.TryGetResult Container |> Option.defaultWith (fun () -> c.CosmosContainer)
let database = p.GetResult(Database, fun () -> c.CosmosDatabase)
let container = p.GetResult(Container, fun () -> c.CosmosContainer)
member val Verbose = p.Contains Verbose
member _.Connect() = connector.ConnectContext(database, container)

Expand Down Expand Up @@ -102,9 +99,9 @@ module Dynamo =
| Some systemName ->
Choice1Of2 systemName
| None ->
let serviceUrl = p.TryGetResult ServiceUrl |> Option.defaultWith (fun () -> c.DynamoServiceUrl)
let accessKey = p.TryGetResult AccessKey |> Option.defaultWith (fun () -> c.DynamoAccessKey)
let secretKey = p.TryGetResult SecretKey |> Option.defaultWith (fun () -> c.DynamoSecretKey)
let serviceUrl = p.GetResult(ServiceUrl, fun () -> c.DynamoServiceUrl)
let accessKey = p.GetResult(AccessKey, fun () -> c.DynamoAccessKey)
let secretKey = p.GetResult(SecretKey, fun () -> c.DynamoSecretKey)
Choice2Of2 (serviceUrl, accessKey, secretKey)
let connector = let timeout = p.GetResult(RetriesTimeoutS, 5.) |> TimeSpan.FromSeconds
let retries = p.GetResult(Retries, 1)
Expand All @@ -113,7 +110,7 @@ module Dynamo =
Equinox.DynamoStore.DynamoStoreConnector(systemName, timeout, retries)
| Choice2Of2 (serviceUrl, accessKey, secretKey) ->
Equinox.DynamoStore.DynamoStoreConnector(serviceUrl, accessKey, secretKey, timeout, retries)
let table = p.TryGetResult Table |> Option.defaultWith (fun () -> c.DynamoTable)
let table = p.GetResult(Table, fun () -> c.DynamoTable)
member _.Connect() = connector.CreateClient().CreateContext("Main", table)

type [<RequireQualifiedAccess; NoComparison; NoEquality>]
Expand Down
19 changes: 9 additions & 10 deletions equinox-shipping/Watchdog/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ open System
module Args =

open Argu
[<NoEquality; NoComparison>]
[<NoEquality; NoComparison; RequireSubcommand>]
type Parameters =
| [<AltCommandLine "-V"; Unique>] Verbose
| [<AltCommandLine "-g"; Mandatory>] ProcessorName of string
Expand All @@ -17,9 +17,9 @@ module Args =
| [<AltCommandLine "-i"; Unique>] IdleDelayMs of int
| [<AltCommandLine "-W"; Unique>] WakeForResults

| [<CliPrefix(CliPrefix.None); Unique; Last>] Cosmos of ParseResults<SourceArgs.Cosmos.Parameters>
| [<CliPrefix(CliPrefix.None); Unique; Last>] Dynamo of ParseResults<SourceArgs.Dynamo.Parameters>
| [<CliPrefix(CliPrefix.None); Unique; Last>] Esdb of ParseResults<SourceArgs.Esdb.Parameters>
| [<CliPrefix(CliPrefix.None)>] Cosmos of ParseResults<SourceArgs.Cosmos.Parameters>
| [<CliPrefix(CliPrefix.None)>] Dynamo of ParseResults<SourceArgs.Dynamo.Parameters>
| [<CliPrefix(CliPrefix.None)>] Esdb of ParseResults<SourceArgs.Esdb.Parameters>
interface IArgParserTemplate with
member p.Usage = p |> function
| Verbose -> "request Verbose Logging. Default: off."
Expand All @@ -29,7 +29,7 @@ module Args =
| TimeoutS _ -> "Timeout (in seconds) before Watchdog should step in to process transactions. Default: 10."

| IdleDelayMs _ -> "Idle delay for scheduler. Default 1000ms"
| WakeForResults _ -> "Wake for all results to provide optimal throughput"
| WakeForResults -> "Wake for all results to provide optimal throughput"

| Cosmos _ -> "specify CosmosDB parameters."
| Dynamo _ -> "specify DynamoDB input parameters"
Expand All @@ -55,7 +55,7 @@ module Args =
| Cosmos a -> Choice1Of3 <| SourceArgs.Cosmos.Arguments(c, a)
| Dynamo a -> Choice2Of3 <| SourceArgs.Dynamo.Arguments(c, a)
| Esdb a -> Choice3Of3 <| SourceArgs.Esdb.Arguments(c, a)
| a -> Args.missingArg $"Unexpected Store subcommand %A{a}"
| a -> failwith $"Unexpected Store subcommand %A{a}"
member x.VerboseStore = match x.Store with
| Choice1Of3 s -> s.Verbose
| Choice2Of3 s -> s.Verbose
Expand Down Expand Up @@ -128,8 +128,7 @@ let main argv =
try let args = Args.parse EnvVar.tryGet argv
try Log.Logger <- LoggerConfiguration().Configure(verbose = args.Verbose).CreateLogger()
try run args |> Async.RunSynchronously; 0
with e when not (e :? Args.MissingArg) && not (e :? System.Threading.Tasks.TaskCanceledException) -> Log.Fatal(e, "Exiting"); 2
with e when not (e :? System.Threading.Tasks.TaskCanceledException) -> Log.Fatal(e, "Exiting"); 2
finally Log.CloseAndFlush()
with Args.MissingArg msg -> eprintfn "%s" msg; 1
| :? Argu.ArguParseException as e -> eprintfn "%s" e.Message; 1
| e -> eprintf "Exception %s" e.Message; 1
with :? Argu.ArguParseException as e -> eprintfn $"%s{e.Message}"; 1
| e -> eprintf $"Exception %s{e.Message}"; 1
28 changes: 14 additions & 14 deletions equinox-shipping/Watchdog/SourceArgs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ module Cosmos =
| LagFreqM _ -> "specify frequency (minutes) to dump lag stats. Default: 1"

type Arguments(c: Args.Configuration, p: ParseResults<Parameters>) =
let discovery = p.TryGetResult Connection |> Option.defaultWith (fun () -> c.CosmosConnection) |> Equinox.CosmosStore.Discovery.ConnectionString
let discovery = p.GetResult(Connection, fun () -> c.CosmosConnection) |> Equinox.CosmosStore.Discovery.ConnectionString
let mode = p.TryGetResult ConnectionMode
let timeout = p.GetResult(Timeout, 5.) |> TimeSpan.FromSeconds
let retries = p.GetResult(Retries, 9)
let maxRetryWaitTime = p.GetResult(RetriesWaitTime, 30.) |> TimeSpan.FromSeconds
let connector = Equinox.CosmosStore.CosmosStoreConnector(discovery, timeout, retries, maxRetryWaitTime, ?mode = mode)
let database = p.TryGetResult Database |> Option.defaultWith (fun () -> c.CosmosDatabase)
let containerId = p.TryGetResult Container |> Option.defaultWith (fun () -> c.CosmosContainer)
let database = p.GetResult(Database, fun () -> c.CosmosDatabase)
let containerId = p.GetResult(Container, fun () -> c.CosmosContainer)
let leaseContainerId = p.GetResult(LeaseContainer, containerId + "-aux")
let fromTail = p.Contains FromTail
let maxItems = p.TryGetResult MaxItems
Expand Down Expand Up @@ -99,9 +99,9 @@ module Dynamo =
| Some systemName ->
Choice1Of2 systemName
| None ->
let serviceUrl = p.TryGetResult ServiceUrl |> Option.defaultWith (fun () -> c.DynamoServiceUrl)
let accessKey = p.TryGetResult AccessKey |> Option.defaultWith (fun () -> c.DynamoAccessKey)
let secretKey = p.TryGetResult SecretKey |> Option.defaultWith (fun () -> c.DynamoSecretKey)
let serviceUrl = p.GetResult(ServiceUrl, fun () -> c.DynamoServiceUrl)
let accessKey = p.GetResult(AccessKey, fun () -> c.DynamoAccessKey)
let secretKey = p.GetResult(SecretKey, fun () -> c.DynamoSecretKey)
Choice2Of2 (serviceUrl, accessKey, secretKey)
let connector = let timeout = p.GetResult(RetriesTimeoutS, 60.) |> TimeSpan.FromSeconds
let retries = p.GetResult(Retries, 9)
Expand All @@ -110,9 +110,9 @@ module Dynamo =
Equinox.DynamoStore.DynamoStoreConnector(systemName, timeout, retries)
| Choice2Of2 (serviceUrl, accessKey, secretKey) ->
Equinox.DynamoStore.DynamoStoreConnector(serviceUrl, accessKey, secretKey, timeout, retries)
let table = p.TryGetResult Table |> Option.defaultWith (fun () -> c.DynamoTable)
let table = p.GetResult(Table, fun () -> c.DynamoTable)
let indexSuffix = p.GetResult(IndexSuffix, "-index")
let indexTable = p.TryGetResult IndexTable |> Option.orElseWith (fun () -> c.DynamoIndexTable) |> Option.defaultWith (fun () -> table + indexSuffix)
let indexTable = p.GetResult(IndexTable, fun () -> defaultArg c.DynamoIndexTable (table + indexSuffix))
let fromTail = p.Contains FromTail
let tailSleepInterval = TimeSpan.FromMilliseconds 500.
let batchSizeCutoff = p.GetResult(MaxItems, 100)
Expand Down Expand Up @@ -142,9 +142,9 @@ module Esdb =
Propulsion.Feed.ReaderCheckpoint.CosmosStore.create Store.Metrics.log (consumerGroup, checkpointInterval) (context, cache)
| Store.Config.Dynamo (context, cache) ->
Propulsion.Feed.ReaderCheckpoint.DynamoStore.create Store.Metrics.log (consumerGroup, checkpointInterval) (context, cache)
| Store.Config.Memory _ | Store.Config.Esdb _ -> Args.missingArg "Unexpected store type"
| Store.Config.Memory _ | Store.Config.Esdb _ -> failwith "Unexpected store type"

type [<NoEquality; NoComparison>] Parameters =
type [<NoEquality; NoComparison; RequireSubcommand>] Parameters =
| [<AltCommandLine "-V">] Verbose
| [<AltCommandLine "-c">] Connection of string
| [<AltCommandLine "-p"; Unique>] Credentials of string
Expand All @@ -154,8 +154,8 @@ module Esdb =
| [<AltCommandLine "-b"; Unique>] MaxItems of int
| [<AltCommandLine "-Z"; Unique>] FromTail

| [<CliPrefix(CliPrefix.None); Unique(*ExactlyOnce is not supported*); Last>] Cosmos of ParseResults<Args.Cosmos.Parameters>
| [<CliPrefix(CliPrefix.None); Unique(*ExactlyOnce is not supported*); Last>] Dynamo of ParseResults<Args.Dynamo.Parameters>
| [<CliPrefix(CliPrefix.None)>] Cosmos of ParseResults<Args.Cosmos.Parameters>
| [<CliPrefix(CliPrefix.None)>] Dynamo of ParseResults<Args.Dynamo.Parameters>
interface IArgParserTemplate with
member p.Usage = p |> function
| Verbose -> "Include low level Store logging."
Expand All @@ -174,7 +174,7 @@ module Esdb =
let startFromTail = p.Contains FromTail
let maxItems = p.GetResult(MaxItems, 100)
let tailSleepInterval = TimeSpan.FromSeconds 0.5
let connectionStringLoggable = p.TryGetResult Connection |> Option.defaultWith (fun () -> c.EventStoreConnection)
let connectionStringLoggable = p.GetResult(Connection, fun () -> c.EventStoreConnection)
let credentials = p.TryGetResult Credentials |> Option.orElseWith (fun () -> c.MaybeEventStoreCredentials)
let discovery = match credentials with Some x -> String.Join(";", connectionStringLoggable, x) | None -> connectionStringLoggable
|> Equinox.EventStoreDb.Discovery.ConnectionString
Expand All @@ -193,7 +193,7 @@ module Esdb =
match p.GetSubCommand() with
| Cosmos cosmos -> Args.TargetStoreArgs.Cosmos (Args.Cosmos.Arguments(c, cosmos))
| Dynamo dynamo -> Args.TargetStoreArgs.Dynamo (Args.Dynamo.Arguments(c, dynamo))
| _ -> Args.missingArg "Must specify `cosmos` or `dynamo` target store when source is `esdb`"
| _ -> p.Raise "Must specify `cosmos` or `dynamo` target store when source is `esdb`"

member _.MonitoringParams(log: ILogger) =
log.Information("EventStoreSource MaxItems {maxItems} ", maxItems)
Expand Down
2 changes: 1 addition & 1 deletion equinox-shipping/Watchdog/Watchdog.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Argu" Version="6.1.1" />
<PackageReference Include="Argu" Version="6.1.4" />
<PackageReference Include="Propulsion.CosmosStore" Version="3.0.0-rc.9.11" />
<PackageReference Include="Propulsion.DynamoStore" Version="3.0.0-rc.9.11" />
<PackageReference Include="Propulsion.EventStoreDb" Version="3.0.0-rc.9.11" />
Expand Down
Loading

0 comments on commit 58e491b

Please sign in to comment.