Skip to content

refactor: replace global AtomicU64 metrics statics with an encapsulated metrics actor or registry #148

Description

@coderabbitai

Summary

crates/weaverd/src/dispatch/act/refactor/metrics.rs currently tracks position error counts using two process-level AtomicU64 statics:

  • POSITION_PARSE_ERROR_COUNT
  • POSITION_CONVERSION_ERROR_COUNT

These are incremented via a PositionMetrics trait whose production implementation (AtomicPositionMetrics) mutates the statics directly. This is global mutable state: it is shared across all concurrent request handlers, cannot be scoped to a single request or test, and requires explicit reset_test_counters() calls and #[serial] test annotations to avoid data races in the test suite.

Problem

  • Test isolation: Tests that exercise any code path invoking AtomicPositionMetrics share state. Without #[serial], parallel test runs produce non-deterministic counter values. The workaround (reset_test_counters()) is fragile and couples tests to global state.
  • Composability: A single AtomicPositionMetrics singleton cannot distinguish errors from different concurrent rename operations or different workspace sessions.
  • Exportability: The statics are private; no clean seam exists to hook them into a metrics exporter without exposing the raw atomics or adding another global singleton.

Proposed Direction

Replace the global statics with an encapsulated metrics actor or a per-instance metrics registry:

  1. Actor approach: Introduce a long-lived MetricsActor task that owns a HashMap<MetricKey, u64> and accepts increment messages over a channel. Each handler receives a MetricsSender handle (a cheaply-cloneable mpsc sender) injected at startup. The actor exposes a snapshot query for tests and for exporter integration.
  2. Registry approach: Use the metrics crate façade (already used elsewhere in the daemon, if applicable) and replace the raw atomics with metrics::counter! calls. This delegates ownership to the metrics crate's global recorder, which can be swapped for a MockRecorder in tests without #[serial].

Either approach eliminates the global statics, removes the need for reset_test_counters(), and provides a clean seam for the export work tracked in issue #142.

Immediate Workaround

Until this is resolved, all tests in metrics.rs that read or mutate the global counters are annotated with #[serial] (from the serial_test crate) and carry a FIXME comment referencing this issue.

Background

Raised as an out-of-scope architectural follow-up from PR #126.
Requested by @leynos.

Related: #142 (metrics export), #125 (structured logging/tracing).

Backlink: #126

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions