Skip to content

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.

Sources

  • src/SAIF.PremiumAudit.Batch/Program.vb
  • src/SAIF.PremiumAudit.Batch/AuditProcessor.vb
  • src/SAIF.PremiumAudit.Batch/App.config