Skip to content

fix: allow restarting a tracker after stop() - #1337

Open
davidberenstein1957 wants to merge 4 commits into
masterfrom
fix/restart-after-stop
Open

fix: allow restarting a tracker after stop()#1337
davidberenstein1957 wants to merge 4 commits into
masterfrom
fix/restart-after-stop

Conversation

@davidberenstein1957

Copy link
Copy Markdown
Collaborator

What

stop() tore down both schedulers but never cleared _start_time, so a later start() returned early with "Already started tracking". The tracker looked started but was never sampled, and the next stop() wrote a row whose duration covered everything since the original start() — including the idle gap — making that row's duration and emissions_rate wrong.

Changes

  • stop() records _paused_at after the final persist, and returns early (with the existing "Tracker already stopped !" warning) if the tracker is already stopped, instead of writing a duplicate row.
  • start() rebuilds the schedulers when they were discarded, and on a restart shifts _start_time by the paused interval rather than re-stamping it. The energy accumulators are deliberately not reset on restart, so shifting keeps duration and the accumulators on the same clock: both cover active time only.

Note: a restarted run stays cumulative, and row 2's duration is now the sum of the active phases rather than wall-clock since the first start().

Verification

New test tests/test_emissions_tracker.py::TestCarbonTracker::test_tracker_can_be_restarted_after_stop — start/2s/stop, 2s pause, start/2s/stop — asserts the scheduler exists again after the second start() and that the second row's duration is ~4 s, not ~6 s. It fails on master and passes with this change. Full suite: 627 passed, 21 skipped.

Closes #1328

🤖 Generated with Claude Code

A second stop() ran a full measurement and wrote a duplicate row through
every output handler. Guard on an explicit _is_stopped flag and return the
cached final_emissions instead. The lock release now happens after the
guard, so a repeat stop no longer retries os.remove.

Closes #1307

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.56%. Comparing base (065d0e6) to head (3faa49a).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1337      +/-   ##
==========================================
+ Coverage   91.39%   91.56%   +0.17%     
==========================================
  Files          49       49              
  Lines        5056     5076      +20     
==========================================
+ Hits         4621     4648      +27     
+ Misses        435      428       -7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

davidberenstein1957 and others added 3 commits August 12, 2026 17:47
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Lock.release() left _has_created_lock True, so a second release()
deleted a lock file that may by then belong to another process.

Rename the stop guard flag to _stopped_at (a timestamp) so start/stop
share one piece of state instead of two.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
start() after a stop() now undoes what stop() tore down, symmetrically:
it takes the lock back (and refuses to restart if another instance grabbed
it meanwhile) and rebuilds the schedulers. The energy accumulators are
kept, so _start_time is shifted by the stopped interval to keep duration
on the same clock as the accumulators.

The output handlers are deliberately left as they are: exit() runs on
every stop() and a later out() re-creates what it cleaned up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@davidberenstein1957
davidberenstein1957 marked this pull request as ready for review August 13, 2026 05:05
@davidberenstein1957
davidberenstein1957 requested a review from a team as a code owner August 13, 2026 05:05
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.

Tracker cannot be restarted: start() after stop() is a no-op and the next row's duration is wrong

1 participant