Batch lifecycle¶
A run of SAIF.PremiumAudit.Batch begins in Sub Main in Program.vb, which
constructs the AuditProcessor batch class and calls Execute. Execute
validates the command line, initialises the data access layer and log streams,
runs the per-audit processing loop, and finalises the run by writing totals and
closing the streams. Every exit path returns a numeric return code that the
Windows Task Scheduler task records as the last result.
Execution flow¶
flowchart TD
MAIN[Sub Main] --> NEW[New AuditProcessor]
NEW --> EXEC[Execute]
EXEC --> VALIDATE[ValidateCommandLine]
VALIDATE -->|Pass| PREPROCESS[PreProcess]
VALIDATE -->|Fail| HELP[WriteHelp + Exit 1]
PREPROCESS -->|Pass| RUN[RunAppLogic]
PREPROCESS -->|Fail| EXIT1[Exit with ReturnCode 2]
RUN --> FINALIZE[Finalization]
FINALIZE --> EXIT2[Exit with ReturnCode]
ValidateCommandLine¶
ValidateCommandLine checks the four positional arguments described in the
overview. It requires Environment to be one of DEV, TEST, or PROD and
requires AuditDate to parse as yyyy-MM-dd and to be no later than the
current date. BatchSize, when supplied, must be an integer between 1 and
5000; RestartCheckpoint, when supplied, must be a positive integer. Any
failure writes the usage text through WriteHelp, records the reason in the
File0 stream, and returns ReturnCode.BadParameter (1) without opening a
database connection.
PreProcess¶
PreProcess resolves the connection string for the requested environment from
App.config, opens the SQL Server connection used by the data access layer, and
verifies it by executing a lightweight probe query. It then creates the three
output streams in the configured log directory, writes the File0 header block
(program name, assembly version, machine name, environment, audit date, batch
size, and restart checkpoint), and loads the PayrollClassCode rate table into
memory so that rate lookups during the loop do not require a round trip. A
failure to open the connection, create a stream, or load the rate table is
logged to File0 and returns ReturnCode.InitializationFailure (2).
RunAppLogic¶
RunAppLogic calls dbo.usp_GetPendingAudits, passing the audit date, batch
size, and restart checkpoint, and receives the eligible PolicyAudit rows
ordered by PolicyAuditId. It iterates the rows one at a time. For each audit
it validates the payroll detail with SAIF.Framework.Validation, recalculates
earned premium from the audited payroll and the class code rate in effect on the
policy effective date, compares the result to the estimated premium, and writes
the difference as a PremiumTransaction row. Each audit is processed inside its
own database transaction so that a failure affects only that audit. After every
100 audits the current PolicyAuditId is written to File0 as a checkpoint line
so that a partial run can be resumed.
Processing pattern¶
| Step | Action | On success | On failure |
|---|---|---|---|
| 1 | Retrieve pending audits via dbo.usp_GetPendingAudits |
Continue to the processing loop | Log to File0 and exit with ReturnCode 3 |
| 2 | Validate payroll detail for the audit (BR-001, BR-002) | Continue to recalculation | Mark the audit Rejected, roll back, log to File2 |
| 3 | Recalculate premium and insert the PremiumTransaction row |
Commit, update PolicyAudit.Status to Posted, log to File1 |
Roll back the audit transaction, log to File2, continue with the next audit |
| 4 | Write run totals (audits read, posted, rejected, failed, net premium adjustment) to File0 | Streams closed and flushed | Log the write failure to File0 and exit with ReturnCode 4 |
| 5 | Compare the failure count to the configured threshold | Exit with ReturnCode 0 | Send the on-call email and exit with ReturnCode 5 |
Batch streams¶
| Stream | Purpose | Audience |
|---|---|---|
File0 |
Control/execution log: header block, checkpoint lines every 100 audits, run totals, and fatal errors | Operations |
File1 |
Success detail report: one line per posted audit with policy number, audited payroll, recalculated premium, and adjustment amount | Operations / Business |
File2 |
Error detail report: one line per rejected or failed audit with policy number, PolicyAuditId, rule id, and exception message |
Operations / On-call |
Return codes¶
| Code | Meaning | Trigger |
|---|---|---|
| 0 (Success) | Processing completed | All audits processed and the failure count is at or below the threshold |
| 1 (BadParameter) | Invalid parameters | ValidateCommandLine failure; usage text written to the console |
| 2 (InitializationFailure) | Initialization failed | Connection could not be opened, a log stream could not be created, or the rate table could not be loaded |
| 3 (RetrievalFailure) | Audit retrieval failed | dbo.usp_GetPendingAudits raised an error or timed out before any audit was processed |
| 4 (FinalizationFailure) | Totals could not be written | The File0 stream could not be flushed or closed at the end of the run |
| 5 (ErrorThresholdExceeded) | Too many per-audit failures | The failure count exceeded ErrorThreshold (default 25); notification email sent |
Error handling¶
Per-record errors¶
Each audit is processed inside its own SQL Server transaction opened at the
start of step 2 and committed at the end of step 3. Any validation failure or
exception raised while processing an audit causes the transaction to roll back,
so no partial PremiumTransaction row and no PolicyAudit.Status change
survive a failed audit. The failure is written to File2 with the policy number,
PolicyAuditId, the business rule id where applicable, and the exception
message, the failure counter is incremented, and the loop continues with the
next audit. Audits that fail this way keep their Pending status and are picked
up again on the next run.
Catastrophic errors¶
Two conditions end a run early. A failure in PreProcess or in the retrieval
call means no audit can be processed, so the run exits immediately with return
code 2 or 3. A run that starts successfully but accumulates more than
ErrorThreshold per-audit failures (default 25, set in App.config) stops the
loop, writes the totals it has, sends the notification email to the on-call
distribution list configured under NotificationRecipients, and exits with
return code 5. In both cases the File0 stream records the last checkpoint
PolicyAuditId, which is the value to pass as RestartCheckpoint on the rerun.
Related documentation¶
- Architecture
- Operations and processes
- Operational runbook
Sources¶
src/SAIF.PremiumAudit.Batch/Program.vbsrc/SAIF.PremiumAudit.Batch/AuditProcessor.vbsrc/SAIF.PremiumAudit.Batch/App.config