Skip to content

Commit 25e8f98

Browse files
TTTPOBclaude
andcommitted
perf: reuse kernel WebSocket connection for multi-cell execution
Previously each cell created a new KernelClient (connect/disconnect cycle). Now _exec_file uses a single kernel_connection context manager for all cells. Also passes timeout to kernel.execute() which was previously ignored (defaulting to 10s). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent aee3252 commit 25e8f98

2 files changed

Lines changed: 39 additions & 31 deletions

File tree

j_cli/commands/exec_cmd.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ def exec_cmd(ctx: Context, session_id: str, code: str | None, file_path: str | N
2626

2727
try:
2828
from j_cli.server import get_kernel_id_for_session
29-
from j_cli.kernel import execute_code
3029

3130
kernel_id = get_kernel_id_for_session(ctx.server_url, session_id, ctx.token)
3231
except Exception as e:
@@ -66,7 +65,7 @@ def _exec_file(ctx: Context, kernel_id: str, file_path: str, cell_spec: str | No
6665
"""Execute cells from a file."""
6766
try:
6867
from j_cli.parser import parse_file, parse_cell_spec
69-
from j_cli.kernel import execute_code
68+
from j_cli.kernel import kernel_connection
7069

7170
parsed = parse_file(file_path)
7271

@@ -84,24 +83,25 @@ def _exec_file(ctx: Context, kernel_id: str, file_path: str, cell_spec: str | No
8483
cell_results = []
8584
all_outputs_human = []
8685

87-
for cell in selected:
88-
result = execute_code(ctx.server_url, ctx.token, kernel_id, cell.source, timeout)
89-
raw_outputs = result.get("outputs", [])
90-
outputs = process_outputs(raw_outputs)
91-
92-
cell_results.append({
93-
"cell_index": cell.index,
94-
"source_preview": cell.source[:80].replace("\n", " "),
95-
"outputs": outputs,
96-
"raw_outputs": raw_outputs,
97-
"execution_count": result.get("execution_count"),
98-
})
99-
100-
if not ctx.use_json:
101-
all_outputs_human.append(f"--- cell {cell.index} ---")
102-
text = format_outputs_human(outputs)
103-
if text:
104-
all_outputs_human.append(text)
86+
with kernel_connection(ctx.server_url, ctx.token, kernel_id) as kernel:
87+
for cell in selected:
88+
result = kernel.execute(cell.source, timeout=timeout)
89+
raw_outputs = result.get("outputs", [])
90+
outputs = process_outputs(raw_outputs)
91+
92+
cell_results.append({
93+
"cell_index": cell.index,
94+
"source_preview": cell.source[:80].replace("\n", " "),
95+
"outputs": outputs,
96+
"raw_outputs": raw_outputs,
97+
"execution_count": result.get("execution_count"),
98+
})
99+
100+
if not ctx.use_json:
101+
all_outputs_human.append(f"--- cell {cell.index} ---")
102+
text = format_outputs_human(outputs)
103+
if text:
104+
all_outputs_human.append(text)
105105

106106
# Write back to notebook
107107
notebook_updated = None

j_cli/kernel.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
11
"""Kernel execution via jupyter-kernel-client (WebSocket)."""
22

3+
from contextlib import contextmanager
4+
35
from jupyter_kernel_client import KernelClient
46

57

8+
@contextmanager
9+
def kernel_connection(server_url: str, token: str | None, kernel_id: str):
10+
"""Context manager that yields a started KernelClient."""
11+
kernel = KernelClient(
12+
server_url=server_url,
13+
token=token,
14+
kernel_id=kernel_id,
15+
)
16+
kernel.start()
17+
try:
18+
yield kernel
19+
finally:
20+
kernel.stop()
21+
22+
623
def execute_code(
724
server_url: str,
825
token: str | None,
@@ -15,14 +32,5 @@ def execute_code(
1532
Returns dict with 'outputs' key containing list of output dicts,
1633
and 'execution_count'.
1734
"""
18-
kernel = KernelClient(
19-
server_url=server_url,
20-
token=token,
21-
kernel_id=kernel_id,
22-
)
23-
kernel.start()
24-
try:
25-
result = kernel.execute(code)
26-
return result
27-
finally:
28-
kernel.stop()
35+
with kernel_connection(server_url, token, kernel_id) as kernel:
36+
return kernel.execute(code, timeout=timeout)

0 commit comments

Comments
 (0)