Skip to content

fix: double-counted metrics and SCIM PATCH replace - #790

Merged
catinspace-au merged 1 commit into
mainfrom
fix/metrics-scim
Oct 10, 2026
Merged

catinspace-au merged 1 commit into
mainfrom
fix/metrics-scim

Conversation

@catinspace-au

@catinspace-au catinspace-au commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Three follow-ups to #789.

  • FastAPI 0.142 records its own http.server.request.duration into whatever MeterProvider is global, and on the engine that is scalo's. So /metrics carried http_server_request_duration_seconds twice, the second family under otel_scope_name="fastapi", and the app status request query counted every engine request twice. The engine API now passes {**FASTAPI_TELEMETRY, "metrics": False}. The KEDA shim is unchanged, it has no scalo histogram to collide with.
  • The schema phase called create_metrics() on every pass, so the daemon built a second MetricsManager and MeterProvider beside ServiceApp's, logged Overriding of current MeterProvider is not allowed, and left the orphan's reader running. create_app now builds SchemaMetrics once on the manager the daemon serves, and the lifespan hands it to bootstrap_clickhouse. The gauges keep their dfe_schema_* names whatever namespace the manager carries. dfe schema apply builds its own manager, once per run.
  • A SCIM group replace on members only ever added. It now swaps the whole set (RFC 7644 section 3.5.2.3), a members[value eq "x"] replace swaps that one member, and a filter matching no member answers 400 noTarget. A path-less add or replace carrying members is honoured, and one carrying none leaves them alone. The member list is worked out before anything is written and stored in one update, so the audit event's added and removed are exactly who changed.

test_daemon_metrics.py builds the daemon's shape in a child process, because the global MeterProvider can only be set once, and checks for one histogram family, one MeterProvider, no override refusal and the dfe_schema_* names. test_schema_metrics.py covers both manager namespaces. test_scim_change_audit.py covers each replace form, the noTarget refusal and the no-change cases. Each fails with its fix reverted.

Done when CI is green on every job.

FastAPI 0.142 records its own request histogram into the global MeterProvider, which on the engine is scalo's. So /metrics carried http_server_request_duration_seconds twice, once from scalo's middleware and once under otel_scope_name="fastapi", and the app status query counted every engine request twice. The engine API now turns FastAPI's request metrics off. The KEDA shim keeps them, it has no scalo histogram.

The schema phase built a fresh scalo MetricsManager on every pass. Under the OpenTelemetry backend that is a new MeterProvider the SDK refuses to install ("Overriding of current MeterProvider is not allowed") and then leaves running beside the real one. The daemon now registers the schema gauges on the manager it already serves on /metrics, under the same dfe_schema_* names. `dfe schema apply` still builds its own, once per run.

A SCIM group PATCH replace only ever added members. It now swaps the whole set, per RFC 7644 section 3.5.2.3. A filtered replace swaps just the member it names, and a filter that matches no member is a 400 noTarget. A path-less replace or add carrying members is honoured too. The new member list is worked out first and written once, so the audit event names only who joined and who left, and a PATCH that changes nothing emits nothing.
@catinspace-au
catinspace-au merged commit e81d2cc into main Oct 10, 2026
22 checks passed
@catinspace-au
catinspace-au deleted the fix/metrics-scim branch October 10, 2026 09:46
@github-actions

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant