Architecture¶
This document explains how azure-functions-doctor is structured internally and why key design choices support deterministic, actionable diagnostics.
Design Objectives¶
The package is intentionally focused:
- Keep diagnostics rule-driven and data-defined (JSON rule assets, not hardcoded checks).
- Preserve exit-code-based CI integration as a first-class concern.
- Add invocation context without requiring heavy runtime dependencies.
- Stay dependency-light and operationally predictable.
High-Level Components¶
Core modules and responsibilities:
__init__.py: public exports and version string.cli.py: Typer-based CLI entrypoint; maps flags toDoctoroptions.doctor.py:Doctorrunner — loads rules, executes handlers, aggregates results.handlers.py:Ruletype,generic_handler, type-based rule dispatch viaHandlerRegistry.config.py: configuration management (reserved for future use; not yet in the runtime path).target_resolver.py: resolves runtime values (Python version, Core Tools version) for version-comparison checks.logging_config.py: internal logging setup.schemas/: JSON schema definitions for rule assets.assets/: built-in rule inventory (e.g.rules/v2.json).
Public API Boundary¶
Public symbols intentionally kept small:
Doctor__version__run_diagnostics()(fromapi.py— programmatic entrypoint)
CLI is the primary consumer. Python import use is for programmatic embedding only.
Module Boundaries¶
Diagnostic Pipeline¶
Doctor.run_all_checks() is the entrypoint for a full diagnostic scan.
Execution flow:
- Load rule asset (
assets/rules/v2.json) or customrules_path. - Validate rule asset against JSON schema.
- Apply profile filter if
--profileis given. - Dispatch each rule to its handler by the rule's
typefield. - Aggregate
SectionResultlist with per-itemCheckResultentries. - Return
list[SectionResult]— overall pass/fail status is derived later by the CLI.
Rule Asset Design¶
Rules are data, not code:
- Each rule is a JSON object with
id,category,label,type,condition, and optionalhint. - Handlers dispatch on the rule's
typefield and evaluateconditionagainst the target project. - New checks can be added without touching Python logic.
See Rule Inventory and RULE_POLICY for the full rule catalogue.
Exit Code Contract¶
The CLI follows a strict exit code contract:
| Exit code | Meaning |
|---|---|
0 |
No checks failed |
1 |
One or more checks failed |
2 |
Usage error (bad arguments) |
CI pipelines can rely on these codes directly. See JSON Output Contract for structured output.
Profile System¶
Profiles allow subsets of rules:
- Profile is a string selector (
minimalorfull), not a file-based system.minimalkeeps only rules whererequired=Truein the rule asset;full(the default) runs all rules. --profile minimalrestricts the scan to required rules only.- Custom profile names raise
ValueError; onlyminimalandfullare accepted.
See Configuration and Minimal Profile.
Key Design Decisions¶
1. JSON rule assets over hardcoded checks¶
Every diagnostic check is defined as a JSON object in the rule inventory (assets/rules/v2.json). New checks are added by appending rule data — no Python handler changes required unless a new rule type is introduced.
2. HandlerRegistry type-based dispatch¶
handlers.py maintains a HandlerRegistry that maps rule type strings to handler functions. The Doctor runner dispatches each rule to its handler by type, enabling extensibility without modifying dispatch logic.
3. Exit code contract¶
cli.py sets exit code 1 explicitly when any check fails. Exit code 0 results from explicit typer.Exit(0) in structured-output paths and normal return in table mode. Exit code 2 is not explicitly coded — it is the default behaviour of Typer/Click when invoked with invalid arguments.
4. String-based profile selection¶
Profiles are not file-based. The --profile flag accepts minimal or full (default). minimal filters rules to those where required=True in the rule asset (Doctor.run_all_checks()). This avoids external profile file management while covering the common use case of gating CI on required rules only.
5. Typer CLI framework¶
The CLI uses Typer for argument parsing, help generation, and shell completion. This was chosen over argparse/Click for its decorator-driven API and automatic type inference from Python type hints.
Related Documents¶
Sources¶
- Azure Functions Python developer reference
- Azure Functions host.json reference
- Supported languages in Azure Functions
See Also¶
- azure-functions-validation — Architecture — Request/response validation and serialization
- azure-functions-openapi — Architecture — API documentation and spec generation
- azure-functions-logging — Architecture — Structured logging with contextvars
- azure-functions-scaffold — Architecture — Project scaffolding CLI
- azure-functions-langgraph — Architecture — LangGraph runtime exposure for Azure Functions