Skip to content

Commit 2fdfa74

Browse files
smflorentinoclaude
andcommitted
chore: add comments explaining non-obvious design decisions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent dbb9146 commit 2fdfa74

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

src/uipath/runtime/logging/_interceptor.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,14 @@ def _redirect_stdout_stderr(self) -> None:
209209
)
210210

211211
def teardown(self) -> None:
212-
"""Restore original logging configuration."""
212+
"""Restore original logging configuration.
213+
214+
IMPORTANT: The ordering below is critical. Flushing must happen before
215+
clearing the context variable and before removing handlers. Otherwise:
216+
- If context is cleared first, the execution filter won't match the
217+
flushed records and they'll be dropped.
218+
- If handlers are removed first, the flushed records have no destination.
219+
"""
213220
# Step 1: Flush LoggerWriter buffers while context and handlers are still active.
214221
# Child mode: flush only this context's buffer from the shared LoggerWriter.
215222
# Master mode: flush ALL remaining buffers before restoring streams.
@@ -266,7 +273,9 @@ def teardown(self) -> None:
266273
if self._owns_handler:
267274
self.log_handler.close()
268275

269-
# Step 5: Only master restores streams (children never replaced them)
276+
# Step 5: Only master restores streams. Children never replaced
277+
# sys.stdout/sys.stderr (they only registered handlers on the loggers),
278+
# so there is nothing for them to restore here.
270279
if not self.execution_id and self.original_stdout and self.original_stderr:
271280
sys.stdout = self.original_stdout
272281
sys.stderr = self.original_stderr

src/uipath/runtime/logging/_writers.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ def __init__(
2424
self.logger = logger
2525
self.level = level
2626
self.min_level = min_level
27+
# Keyed by current_execution_id (None for master context).
28+
# A single shared buffer would interleave partial lines from
29+
# concurrent async tasks writing to the same sys.stdout.
2730
self._buffers: dict[str | None, str] = {}
2831
self.sys_file = sys_file
2932
self._in_logging = False # Recursion guard
@@ -75,7 +78,11 @@ def flush(self) -> None:
7578
self._in_logging = False
7679

7780
def flush_all(self) -> None:
78-
"""Flush all execution contexts' buffered messages. Called by master teardown."""
81+
"""Flush all execution contexts' buffered messages. Called by master teardown.
82+
83+
Intentionally ignores current_execution_id — iterates all keys
84+
directly so that no context's partial lines are lost.
85+
"""
7986
if self._in_logging:
8087
return
8188

0 commit comments

Comments
 (0)