Skip to content

Commit a85be35

Browse files
perf: defer API run creation until first emission upload
Skip POST /runs during tracker startup and create the run lazily on the first live_out/out call when an experiment id is configured. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 1f759d9 commit a85be35

2 files changed

Lines changed: 52 additions & 8 deletions

File tree

codecarbon/output_methods/http.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,28 @@ def __init__(
4949
):
5050
self.endpoint_url: str = endpoint_url
5151
self.api = ApiClient(
52-
experiment_id=experiment_id,
5352
endpoint_url=endpoint_url,
53+
experiment_id=experiment_id,
5454
api_key=api_key,
5555
conf=conf,
56+
create_run_automatically=False,
5657
)
5758
self.run_id = self.api.run_id
5859

59-
def live_out(self, _, delta: EmissionsData):
60-
# Called at regular intervals
60+
def _ensure_api_run(self) -> None:
61+
if self.api.run_id is None and self.api.experiment_id is not None:
62+
self.api._create_run(self.api.experiment_id)
63+
self.run_id = self.api.run_id
64+
65+
def _emit(self, delta: EmissionsData) -> None:
6166
try:
67+
self._ensure_api_run()
6268
self.api.add_emission(dataclasses.asdict(delta))
6369
except Exception as e:
6470
logger.error(e, exc_info=True)
6571

72+
def live_out(self, _, delta: EmissionsData):
73+
self._emit(delta)
74+
6675
def out(self, _, delta: EmissionsData):
67-
# Called on exit
68-
try:
69-
self.api.add_emission(dataclasses.asdict(delta))
70-
except Exception as e:
71-
logger.error(e, exc_info=True)
76+
self._emit(delta)

tests/output_methods/test_http.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,45 @@ def test_codecarbon_api_live_out(self):
147147
api_output.live_out(None, self.emissions_data)
148148
self.mock_add_emission.assert_called_once()
149149

150+
def test_codecarbon_api_live_out_creates_run_when_missing(self):
151+
conf = {
152+
"os": "linux",
153+
"python_version": "3.12",
154+
"codecarbon_version": "2.0",
155+
"cpu_count": 4,
156+
"cpu_model": "CPU",
157+
"gpu_count": 0,
158+
"gpu_model": "",
159+
"longitude": 0.0,
160+
"latitude": 0.0,
161+
"region": "EU",
162+
"provider": "AWS",
163+
"ram_total_size": 16.0,
164+
"tracking_mode": "machine",
165+
}
166+
167+
with patch(
168+
"codecarbon.output_methods.http.ApiClient._create_run"
169+
) as mock_create_run:
170+
api_output = CodeCarbonAPIOutput(
171+
endpoint_url="http://test.com",
172+
experiment_id="exp-1",
173+
api_key=self.api_key,
174+
conf=conf,
175+
)
176+
api_output.api.run_id = None
177+
178+
def create_run(experiment_id):
179+
api_output.api.run_id = "run-created"
180+
return "run-created"
181+
182+
mock_create_run.side_effect = create_run
183+
api_output.live_out(None, self.emissions_data)
184+
185+
mock_create_run.assert_called_once_with("exp-1")
186+
self.assertEqual(api_output.api.run_id, "run-created")
187+
self.assertEqual(api_output.run_id, "run-created")
188+
150189
@patch("codecarbon.output_methods.http.logger.error")
151190
def test_codecarbon_live_out_api_call_failure(self, mock_logger):
152191
self.mock_add_emission.side_effect = Exception("Test exception")

0 commit comments

Comments
 (0)