Skip to content

Commit e92c87f

Browse files
fix(py): properly handle mutliple runtimes in the reflection api (#3970)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent b4da586 commit e92c87f

File tree

4 files changed

+29
-14
lines changed

4 files changed

+29
-14
lines changed

‎py/packages/genkit/src/genkit/ai/_base.py‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"""Base/shared implementation for Genkit user-facing API."""
1818

1919
import asyncio
20+
import os
2021
import threading
2122
from collections.abc import Coroutine
2223
from http.server import HTTPServer
@@ -39,6 +40,9 @@
3940

4041
T = TypeVar('T')
4142

43+
_instance_count = -1
44+
_instance_lock = threading.Lock()
45+
4246

4347
class GenkitBase(GenkitRegistry):
4448
"""Base class with shared infra for Genkit instances (sync and async)."""
@@ -58,6 +62,11 @@ def __init__(
5862
server.
5963
"""
6064
super().__init__()
65+
global _instance_count
66+
global _instance_lock
67+
with _instance_lock:
68+
_instance_count += 1
69+
self.id = f'{os.getpid()}-{_instance_count}'
6170
self._initialize_server(reflection_server_spec)
6271
self._initialize_registry(model, plugins)
6372
define_generate_action(self.registry)
@@ -165,10 +174,10 @@ def _start_server(self, spec: ServerSpec, loop: asyncio.AbstractEventLoop) -> No
165174
"""
166175
httpd = HTTPServer(
167176
(spec.host, spec.port),
168-
make_reflection_server(registry=self.registry, loop=loop),
177+
make_reflection_server(registry=self.registry, loop=loop, id=self.id),
169178
)
170179
# We need to write the runtime file closest to the point of starting up
171180
# the server to avoid race conditions with the manager's runtime
172181
# handler.
173-
init_default_runtime(spec)
182+
init_default_runtime(spec, self.id)
174183
httpd.serve_forever()

‎py/packages/genkit/src/genkit/ai/_server.py‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def url(self) -> str:
6363
def create_runtime(
6464
runtime_dir: str,
6565
reflection_server_spec: ServerSpec,
66+
id: str,
6667
at_exit_fn: Callable[[Path], None] | None = None,
6768
) -> Path:
6869
"""Create a runtime configuration for use with the genkit CLI.
@@ -87,7 +88,7 @@ def create_runtime(
8788
runtime_file_path = Path(os.path.join(runtime_dir, runtime_file_name))
8889
metadata = json.dumps({
8990
'reflectionApiSpecVersion': 1,
90-
'id': f'{os.getpid()}',
91+
'id': id,
9192
'pid': os.getpid(),
9293
'genkitVersion': 'py/' + DEFAULT_GENKIT_VERSION,
9394
'reflectionServerUrl': reflection_server_spec.url,
@@ -104,11 +105,7 @@ def cleanup_runtime() -> None:
104105
return runtime_file_path
105106

106107

107-
def init_default_runtime(spec: ServerSpec) -> None:
108+
def init_default_runtime(spec: ServerSpec, id: str) -> None:
108109
"""Initialize the runtime for the Genkit instance."""
109110
runtimes_dir = os.path.join(os.getcwd(), '.genkit/runtimes')
110-
create_runtime(
111-
runtime_dir=runtimes_dir,
112-
reflection_server_spec=spec,
113-
at_exit_fn=os.remove,
114-
)
111+
create_runtime(runtime_dir=runtimes_dir, reflection_server_spec=spec, id=id, at_exit_fn=os.remove)

‎py/packages/genkit/src/genkit/core/reflection.py‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
def make_reflection_server(
7777
registry: Registry,
7878
loop: asyncio.AbstractEventLoop,
79+
id: str,
7980
encoding='utf-8',
8081
quiet=True,
8182
):
@@ -113,11 +114,19 @@ def do_GET(self) -> None: # noqa: N802
113114
For the /api/actions endpoint, returns a JSON object mapping action
114115
keys to their metadata, including input/output schemas.
115116
"""
116-
if urllib.parse.urlparse(self.path).path == '/api/__health':
117+
parsed_url = urllib.parse.urlparse(self.path)
118+
if parsed_url.path == '/api/__health':
119+
query_params = urllib.parse.parse_qs(parsed_url.query)
120+
expected_id = query_params.get('id', [None])[0]
121+
if expected_id is not None and expected_id != id:
122+
self.send_response(500)
123+
self.end_headers()
124+
return
125+
117126
self.send_response(200, 'OK')
118127
self.end_headers()
119128

120-
elif self.path == '/api/actions':
129+
elif parsed_url.path == '/api/actions':
121130
self.send_response(200)
122131
self.send_header('content-type', 'application/json')
123132
self.end_headers()

‎py/packages/genkit/tests/genkit/veneer/server_test.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,19 @@ def test_create_runtime() -> None:
3939
spec = ServerSpec(port=3100)
4040

4141
# Test runtime file creation
42-
runtime_path = create_runtime(temp_dir, spec)
42+
runtime_path = create_runtime(temp_dir, spec, '123')
4343
assert runtime_path.exists()
4444

4545
# Verify file content
4646
content = json.loads(runtime_path.read_text(encoding='utf-8'))
4747
assert isinstance(content, dict)
48-
assert 'id' in content
48+
assert content['id'] == '123'
4949
assert 'pid' in content
5050
assert content['reflectionServerUrl'] == 'http://localhost:3100'
5151
assert 'timestamp' in content
5252

5353
# Test directory creation
5454
new_dir = os.path.join(temp_dir, 'new_dir')
55-
runtime_path = create_runtime(new_dir, spec)
55+
runtime_path = create_runtime(new_dir, spec, '123')
5656
assert os.path.exists(new_dir)
5757
assert runtime_path.exists()

0 commit comments

Comments
 (0)