Skip to content

Flask init_app() overwrites the previous handle without disposing it #20

Description

@AndresL230

Flask init_app() overwrites the previous handle without disposing it

Severity: Medium
Affected repos: middleware-python
Component boundary: middleware-python Flask adapter

Symptom

The Flask extension's init_app() pattern allows the same ReCost() instance to bind to multiple Flask apps. Each call to init_app() invokes init(config) and stores the result in self._handle, overwriting the previous handle. The overwritten handle is never disposed: its flush timer keeps running, its transport thread keeps living, its interceptor patches stay installed.

Evidence

middleware-python/recost/frameworks/flask.pyinit_app() does self._handle = init(config) with no prior self._handle.dispose().

Impact

  • Tests that register the extension twice (common pattern in pytest) leak threads.
  • Apps that re-init the extension on config reload leak timers and may emit interleaved telemetry for the same project.

Fix recommendation

def init_app(self, app: Flask, config: Optional[RecostConfig] = None, **kwargs: Any) -> None:
    if self._handle is not None:
        self._handle.dispose()
        self._handle = None
    if config is None:
        config = RecostConfig(**kwargs)
    self._handle = init(config)

Document: "Calling init_app() again disposes the previous instance. Only one app is active per ReCost instance at a time."

Verification

  • Test: call init_app(app1), then init_app(app2), assert threading.active_count() does not grow.

Related

Relates to existing #4 (Module-level state races: _handle, install/uninstall, init-vs-dispose). This is the specific Flask-adapter symptom of that broader concern.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions