Skip to content

Aggregator is not thread-safe — flush vs. ingest race #1

Description

@AndresL230

Summary

recost/_aggregator.py:127-132's flush() iterates self._buckets.values() while user threads concurrently call ingest() (via interceptor wrappers, which run on whatever thread issued the HTTP request). The flush is driven by a background threading.Timer. Concurrent dict mutation during iteration raises RuntimeError: dictionary changed size during iteration.

This is a real race under any non-trivial load. There is no lock anywhere in Aggregator.

Fix

Wrap ingest, flush, and would_overflow with a threading.RLock. Add a regression test that pumps N worker threads into ingest while the timer thread calls flush.

Files

  • recost/_aggregator.py
  • tests/test_aggregator.py

Priority

P0 — corrupts telemetry / crashes the timer thread under load.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Blocking / shipping brokenbugSomething isn't workingruntimeRuntime / behavioral bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions