Skip to content

Process lifecycle: no atexit flush, no signal handlers, dispose can leak threads #6

Description

@AndresL230

Summary

Two related lifecycle gaps:

1. No atexit / signal handler

The flush timer is a daemon thread — when the process exits normally (sys.exit(), end of __main__, AWS Lambda invocation completes, SIGTERM in a container), the daemon thread is killed and the current aggregator bucket is lost. Cron jobs, Lambdas, batch scripts, and one-shot CLIs report nothing unless the user manually calls handle.dispose().

2. Dispose during connect leaks FDs

recost/_transport.py:133-146, 199-210's dispose() sets self._running = False and queues a sentinel. If the loop is currently inside websockets.connect(url) (blocking await on TCP connect), the sentinel sits in the queue until the connect either succeeds or hits the OS TCP timeout (~75s on Linux). thread.join(timeout=2.0) returns without joining. The daemon thread + open socket FD leak until process exit. In long-lived processes that call init()/dispose() many times (test suites, Flask dev server with reload), FDs accumulate.

Fix

  • In init(), register atexit.register(_final_flush) and (optionally) signal.signal(SIGTERM, ...). Make handlers idempotent. Respect shutdown_flush_timeout_ms. Provide auto_shutdown_handlers=False opt-out.
  • On dispose, loop.call_soon_threadsafe(loop.stop) and cancel pending tasks. Then join with a timeout derived from shutdown_flush_timeout_ms (currently hardcoded 5s) and log if the thread didn't exit.

Files

  • recost/_init.py
  • recost/_transport.py
  • tests/test_init.py

Priority

P1 — short-lived processes report nothing; long-lived test suites leak FDs.

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

    P1Should fix before next releasebugSomething 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