Skip to content

Run lifecycle

Main constructs Program and calls Run(). Because ArgumentContainer declares no properties, argument resolution always succeeds and the application always reaches Execute(), which performs the entire keyword-sync operation before Finish() runs as a no-op.

Execution flow

flowchart TD
    MAIN[Main] --> RUN["Program.Run()"]
    RUN --> ARGS["CreateArgumentContainer(args)<br>new ArgumentContainer(args)"]
    ARGS --> RESOLVE["Arguments.ResolveArguments()<br>always succeeds - no arguments declared"]
    RESOLVE -->|Invalid - unreachable here| FAIL["Write failures to Console.Error<br>ExitCode = 1<br>application never runs"]
    RESOLVE -->|Valid| REG["RegisterAppDependencies(builder)"]
    REG --> BUILD["Build container + CreateApplication(context)<br>new OnBaseKeywordSyncRunner(...)"]
    BUILD --> INIT["Initialize()<br>no-op"]
    INIT --> ZERO["ExitCode = 0"]
    ZERO --> EXEC["Execute()<br>keyword sync operation"]
    EXEC --> FIN["Finish()<br>no-op"]
    FIN --> DISPOSE["Dispose() + WriteFooter()"]
    DISPOSE --> ECHO["Print 'Exit Code: n'"]
    EXEC -.->|Unhandled Exception| ERR5["ExitCode = 5"]

Argument resolution

ArgumentContainer declares no properties, so BuildArgumentResolvers adds nothing beyond the inherited base call. ResolveArguments() therefore always succeeds, and the exit-code-1 argument-validation path is unreachable for this application*. See Arguments for the complete (empty) contract.

Dependency registration

RegisterAppDependencies calls builder.RegisterCommonDependencies(Environment.UserName, new[] { typeof(Program).Assembly }) with no DatabaseConfig arguments, so no unit-of-work or database connection is ever registered. It also registers SAIF.Services.LogService as ILogService (never resolved) and calls builder.ConfigureOpenTelemetry(options => { options.Owner = "Documents"; }). See Architecture and Dependencies for the full registration table.

Initialize

OnBaseKeywordSyncRunner.Initialize() has an empty body — no resource acquisition or preflight checks. The Imaging API client is instead constructed inside Execute().

Step Action On failure
1 No-op —

Execute

The entire business operation runs in Execute(). A one-paragraph summary follows; the step-by-step logic is documented per operation under Operations and processes.

Processing pattern

Step Action On success On failure
1 Log start, read OnBaseKeywordSync.onbaseasync, construct ImagingApiClient Continue to clearing invalid person syncs Exception → LogError/LogException → rethrow → exit 5
2 Clear invalid person keyword syncs, then retrieve and order unprocessed keyword syncs Continue to sync Exception → rethrow → exit 5
3 Sync the batch with OnBase (per-record decision, send, mark processed) Log per-record output, batch completes Any record's failure aborts the remaining batch — no per-record isolation*

Finish

OnBaseKeywordSyncRunner.Finish() has an empty body — no explicit teardown, totals, or notification is emitted. This is a finding, not an omission.

Exit codes

Exit codes are inherited from the SaifConsoleException hierarchy. The table below records which conditions in this application produce each code.

Exit code Exception Triggered by
0 — Execute() and Finish() complete without throwing
1 Argument validation / BadParameterException Not used — no arguments are declared and no BadParameterException is thrown*
2 DatabaseErrorException Not used — no database access exists
3 DataErrorException Not used
4 FileInputOutputException Not used
5 Unhandled exception Any exception rethrown from Execute() — Imaging API HTTP failure, OnBase WCF fault/timeout, missing customquerymappings entry, MarkProcessed failure, or a configuration key that fails to convert
6 NoDataFoundException Not used — an empty unprocessed set simply logs a zero-record summary and exits 0
n/a CustomErrorException Not used — no CustomErrorException is constructed anywhere

In practice the observable contract is binary: 0 on success, 5 on any failure.

Error handling

Recoverable errors

None. There is no per-record error isolation: one failed record aborts the remaining batch, and already-processed records are not rolled back*.

Fatal errors

OnBaseKeywordSyncRunner.Execute wraps the whole operation in a try/catch (Exception ex) that logs the message, calls LogService.LogException(ex), then rethrows. ProgramRunnerBase.Run catches the rethrown exception; since the application never throws a SaifConsoleException subclass, every failure maps to exit code 5†.

Note: Statements marked with † are derived from dependency library documentation via the Legends CLI. Statements marked with * were inferred from code structure or contextual evidence.

Sources

  • OnBaseKeywordSync/Program.cs
  • OnBaseKeywordSync/OnBaseKeywordSyncRunner.cs
  • OnBaseKeywordSync/Services/ImagingApiClient.cs
  • OnBaseKeywordSync/Services/KeywordUpdater.cs