наблюдаемость: ввести безопасный контракт метрик
CI / Rust Checks (pull_request) Successful in 6m15s
CI / UI Checks (pull_request) Successful in 5s
CI / Community Image Smoke (pull_request) Successful in 4m25s
CI / Frontend E2E (pull_request) Successful in 5m17s
CI / Deploy (pull_request) Has been skipped
CI / Rust Checks (push) Successful in 6m9s
CI / UI Checks (push) Successful in 5s
CI / Community Image Smoke (push) Successful in 1m3s
CI / Frontend E2E (push) Successful in 3m47s
CI / Deploy (push) Failing after 3s

This commit is contained in:
2026-07-31 05:04:01 +03:00
parent ec2453c00f
commit 9b1a739e39
50 changed files with 3066 additions and 433 deletions
+24 -1
View File
@@ -49,6 +49,8 @@ def package_category(name: str, manifest_path: Path, workspace_root: Path) -> st
return "app"
if name == "crank-core":
return "core"
if name == "crank-metrics":
return "metrics"
if name == "crank-observability":
return "observability"
if name == "crank-registry":
@@ -92,6 +94,23 @@ def dependency_package_ids(raw_package: dict[str, Any], packages_by_name: dict[s
return dependency_ids
def direct_dependency_violations(raw_package: dict[str, Any]) -> list[Violation]:
package_name = raw_package["name"]
if package_name in {"crank-metrics", "crank-observability"}:
return []
return [
Violation(
source=package_name,
dependency="metrics",
reason="production crates must record metrics through crank-metrics",
)
for dependency in raw_package.get("dependencies", [])
if dependency["name"] == "metrics"
and dependency.get("kind") != "dev"
]
def boundary_reason(source: Package, dependency: Package) -> str | None:
if source.category == "app":
if dependency.category == "app":
@@ -101,7 +120,10 @@ def boundary_reason(source: Package, dependency: Package) -> str | None:
if dependency.category == "app":
return "workspace crates must not depend on apps"
if source.category == "observability":
if source.category == "metrics":
return "crank-metrics must not depend on other workspace crates"
if source.category == "observability" and dependency.category != "metrics":
return "crank-observability must not depend on other workspace crates"
if (
@@ -133,6 +155,7 @@ def find_violations(metadata: dict[str, Any]) -> list[Violation]:
for source in sorted(packages.values(), key=lambda package: package.name):
raw_package = raw_packages_by_id[source.id]
violations.extend(direct_dependency_violations(raw_package))
for dependency_id in dependency_package_ids(raw_package, packages_by_name):
dependency = packages[dependency_id]
reason = boundary_reason(source, dependency)
+8
View File
@@ -47,6 +47,13 @@ check_no_match \
'^\s*use\s+(axum|sqlx)(::|[;\{])' \
"$ROOT_DIR/crates/crank-runtime/src"
check_no_match \
"product modules must record metrics only through crank-metrics" \
'(^|[^[:alnum:]_])(::)?metrics::(counter|gauge|histogram)!' \
"$ROOT_DIR/apps" \
"$ROOT_DIR/crates" \
--glob '!**/crank-metrics/**'
if (( status != 0 )); then
cat >&2 <<'EOF'
@@ -58,6 +65,7 @@ Rules:
- core remains framework/storage agnostic;
- registry remains storage-only and HTTP-client agnostic;
- runtime remains execution-only and storage/framework agnostic.
- names and labels of metrics remain inside the typed crank-metrics contract.
EOF
fi