Skip to content

metrics: fix application_instances_per_channel disagreeing with UI instance counts - #1580

Draft
riyacore404 wants to merge 1 commit into
flatcar:mainfrom
riyacore404:fix/1562-app-instances-per-channel-metric
Draft

metrics: fix application_instances_per_channel disagreeing with UI instance counts#1580
riyacore404 wants to merge 1 commit into
flatcar:mainfrom
riyacore404:fix/1562-app-instances-per-channel-metric

Conversation

@riyacore404

Copy link
Copy Markdown

application_instances_per_channel metric undercounts/miscounts instances

The nebraska_application_instances_per_channel gauge had three bugs relative
to the rest of the codebase:

  1. Dead instances counted forever — the query never filtered on
    last_check_for_updates, so instances that stopped checking in stayed in
    the metric indefinitely instead of aging out like every other
    activity-based query (GetApp, GetApps, GetInstances, etc).
  2. Instances with no channel silently dropped — the query used comma
    joins across groups/channel, so any instance whose group had no
    channel assigned (groups.channel_id can be NULL) disappeared from the
    metric entirely rather than being counted.
  3. amd64/arm64 channels merged into one series — the query grouped only
    by channel name, so two channels sharing a name across architectures
    (e.g. "stable" for amd64 and arm64) were folded into a single row.

This fixes all three: adds the same freshness filter used elsewhere, switches
to LEFT JOIN for groups/channel so channel-less instances land in an
explicit "no channel" bucket instead of vanishing, and adds arch to the
grouping so per-architecture counts are reported separately.

Fixes #1562

How to use

No config or API changes — the fix is internal to how
GetAppInstancesPerChannelMetrics computes the application_instances_per_channel
Prometheus gauge. Reviewers can validate by scraping /metrics on a
Nebraska instance with some inactive instances and/or a channel-less group
and confirming the counts now match what's shown in the instances UI.

Note: this PR adds a new arch label to the application_instances_per_channel
gauge. This is a breaking change for any existing dashboards/alerts that group
by application/version/channel alone — they'll now see one series per
(channel, arch) pair instead of one per channel. Flagging this explicitly in
case maintainers would rather split the label change into a separate PR from
the activity-window/no-channel fixes.

Testing done

Added/updated unit tests in backend/pkg/api/metrics_test.go covering all
three bugs, run against sample_data.sql via the local Postgres test service:

## Test Results

```bash
cd backend
docker compose -f ./docker-compose.test.yaml up -d postgres
NEBRASKA_DB_URL="postgres://postgres:nebraska@127.0.0.1:8001/nebraska_tests?sslmode=disable&connect_timeout=10"
go test ./pkg/api/... -run 'TestGetAppInstancesPerChannelMetrics' -v
docker compose -f ./docker-compose.test.yaml down

Output

=== RUN TestGetAppInstancesPerChannelMetrics
--- PASS: TestGetAppInstancesPerChannelMetrics (0.06s)
=== RUN TestGetAppInstancesPerChannelMetricsExcludesStaleInstances
--- PASS: TestGetAppInstancesPerChannelMetricsExcludesStaleInstances (0.07s)
=== RUN TestGetAppInstancesPerChannelMetricsIncludesGroupsWithoutChannel
--- PASS: TestGetAppInstancesPerChannelMetricsIncludesGroupsWithoutChannel (0.07s)
=== RUN TestGetAppInstancesPerChannelMetricsSeparatesArch
--- PASS: TestGetAppInstancesPerChannelMetricsSeparatesArch (0.07s)
PASS
ok github.com/flatcar/nebraska/backend/pkg/api 0.342s

All targeted tests pass successfully.

Note: I wasn't able to run the full code-checks (golangci-lint) target locally due to environment constraints. Happy to address any lint feedback from CI.


- [ ] Changelog entries added in the respective `changelog/` directory (user-facing change, bug fix, security fix, update)
- [ ] Inspected CI output for image differences: `/boot` and `/usr` size, packages, list files for any missing binaries, kernel modules, config files, kernel modules, etc.

<!-- For coreos-overlay ebuild modifications that include a CROS_WORKON_COMMIT bump, did you bump too the ebuild revision ? -->

Copilot AI lite review requested due to automatic review settings August 13, 2026 17:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes the nebraska_application_instances_per_channel Prometheus gauge to align with UI instance counts by making the underlying query consistent with the rest of the “active instance” logic and by preventing instances from being dropped/merged incorrectly.

Changes:

  • Add an activity-window filter (last_check_for_updates within validityInterval) to stop counting stale instances.
  • Switch to LEFT JOIN + COALESCE so instances in groups without a channel are still counted (in an explicit “no channel” bucket).
  • Add arch to the grouping and metric labels to avoid merging same-named channels across architectures, and update unit tests accordingly.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
backend/pkg/metrics/metrics.go Adds arch label handling when exporting the gauge.
backend/pkg/api/types/metrics.go Extends the metric row type with an Arch field (with -1 sentinel for no-channel).
backend/pkg/api/metrics_test.go Adds/updates tests to cover stale-instance filtering, channel-less groups, and arch separation.
backend/pkg/api/internal/dbreads/metrics.go Rewrites the SQL query to apply the freshness filter, use LEFT JOIN, and group by arch.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 150 to +154
for _, metric := range aipcMetrics {
appInstancePerChannelGaugeMetric.WithLabelValues(metric.ApplicationName, metric.Version, metric.ChannelName).Set(float64(metric.InstancesCount))
archLabel := noChannelArchLabel
if metric.Arch >= 0 {
archLabel = types.Arch(uint(metric.Arch)).String()
}
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.

metrics: application_instances_per_channel disagrees with the instance counts shown in the UI

2 participants