indexify 0.3.3__tar.gz → 0.3.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {indexify-0.3.3 → indexify-0.3.5}/PKG-INFO +3 -3
- {indexify-0.3.3 → indexify-0.3.5}/pyproject.toml +4 -4
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/cli/cli.py +4 -2
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/executor.py +6 -4
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/function_executor.py +18 -0
- indexify-0.3.5/src/indexify/executor/function_executor/health_checker.py +80 -0
- indexify-0.3.5/src/indexify/executor/function_executor/server/client_configuration.py +20 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/server/subprocess_function_executor_server.py +1 -2
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py +0 -5
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/single_task_runner.py +31 -3
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/task_fetcher.py +4 -3
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/handlers/run_function/handler.py +17 -17
- indexify-0.3.5/src/indexify/function_executor/info.py +16 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/main.py +2 -1
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/function_executor.proto +26 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/function_executor_pb2.py +11 -3
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/function_executor_pb2.pyi +32 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/function_executor_pb2_grpc.py +94 -0
- indexify-0.3.3/src/indexify/function_executor/proto/configuration.py → indexify-0.3.5/src/indexify/function_executor/proto/server_configuration.py +0 -2
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/server.py +1 -1
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/service.py +29 -6
- {indexify-0.3.3 → indexify-0.3.5}/README.md +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/README.md +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/api_objects.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/downloader.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/function_executor_state.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/invocation_state_client.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/server/function_executor_server.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/server/function_executor_server_factory.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/task_input.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/task_output.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/runtime_probes.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/task_reporter.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/task_runner.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/README.md +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/handlers/run_function/function_inputs_loader.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/handlers/run_function/request_validator.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/handlers/run_function/response_helper.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/initialize_request_validator.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/invocation_state/invocation_state_proxy_server.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/invocation_state/proxied_invocation_state.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/invocation_state/response_validator.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/message_validator.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/utils/README.md +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/utils/http_client.py +0 -0
- {indexify-0.3.3 → indexify-0.3.5}/src/indexify/utils/logging.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: indexify
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.5
|
4
4
|
Summary: Open Source Indexify components and helper tools
|
5
5
|
Home-page: https://github.com/tensorlakeai/indexify
|
6
6
|
License: Apache 2.0
|
@@ -17,13 +17,13 @@ Classifier: Programming Language :: Python :: 3.13
|
|
17
17
|
Requires-Dist: grpcio (==1.68.1)
|
18
18
|
Requires-Dist: grpcio-tools (==1.68.1)
|
19
19
|
Requires-Dist: httpx-sse (>=0.4.0,<0.5.0)
|
20
|
-
Requires-Dist: httpx[http2] (>=0.
|
20
|
+
Requires-Dist: httpx[http2] (>=0.27,<0.28)
|
21
21
|
Requires-Dist: nanoid (>=2.0.0,<3.0.0)
|
22
22
|
Requires-Dist: pydantic (==2.10.4)
|
23
23
|
Requires-Dist: pyyaml (>=6,<7)
|
24
24
|
Requires-Dist: rich (>=13.9.2,<14.0.0)
|
25
25
|
Requires-Dist: structlog (>=24.4.0,<25.0.0)
|
26
|
-
Requires-Dist: tensorlake (>=0.1.
|
26
|
+
Requires-Dist: tensorlake (>=0.1.11)
|
27
27
|
Requires-Dist: typer (>=0.12,<0.13)
|
28
28
|
Project-URL: Repository, https://github.com/tensorlakeai/indexify
|
29
29
|
Description-Content-Type: text/markdown
|
@@ -1,7 +1,7 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "indexify"
|
3
3
|
# Incremented if any of the components provided in this packages are updated.
|
4
|
-
version = "0.3.
|
4
|
+
version = "0.3.5"
|
5
5
|
description = "Open Source Indexify components and helper tools"
|
6
6
|
authors = ["Tensorlake Inc. <support@tensorlake.ai>"]
|
7
7
|
license = "Apache 2.0"
|
@@ -18,12 +18,12 @@ function-executor = "indexify.function_executor.main:main"
|
|
18
18
|
python = "^3.9"
|
19
19
|
structlog = "^24.4.0"
|
20
20
|
pyyaml = "^6"
|
21
|
-
httpx = { version = "^0.
|
21
|
+
httpx = { version = "^0.27", extras = ["http2"] }
|
22
22
|
grpcio = "1.68.1"
|
23
23
|
|
24
24
|
# Function Executor only
|
25
25
|
grpcio-tools = "1.68.1"
|
26
|
-
tensorlake = "
|
26
|
+
tensorlake = ">=0.1.11"
|
27
27
|
|
28
28
|
# Executor only
|
29
29
|
pydantic = "2.10.4"
|
@@ -36,7 +36,7 @@ nanoid = "^2.0.0"
|
|
36
36
|
|
37
37
|
[tool.poetry.group.dev.dependencies]
|
38
38
|
black = "^24.10.0"
|
39
|
-
pylint = "^
|
39
|
+
pylint = "^3.3.0"
|
40
40
|
parameterized = "^0.9.0"
|
41
41
|
|
42
42
|
[build-system]
|
@@ -219,12 +219,13 @@ def executor(
|
|
219
219
|
)
|
220
220
|
|
221
221
|
id = nanoid.generate()
|
222
|
+
executor_version = version("indexify")
|
222
223
|
logger.info(
|
223
224
|
"starting executor",
|
224
225
|
server_addr=server_addr,
|
225
226
|
config_path=config_path,
|
226
227
|
executor_id=id,
|
227
|
-
executor_version=
|
228
|
+
executor_version=executor_version,
|
228
229
|
executor_cache=executor_cache,
|
229
230
|
ports=ports,
|
230
231
|
functions=function_uris,
|
@@ -247,7 +248,8 @@ def executor(
|
|
247
248
|
exit(1)
|
248
249
|
|
249
250
|
Executor(
|
250
|
-
id,
|
251
|
+
id=id,
|
252
|
+
version=executor_version,
|
251
253
|
server_addr=server_addr,
|
252
254
|
config_path=config_path,
|
253
255
|
code_path=executor_cache,
|
@@ -21,7 +21,8 @@ from .task_runner import TaskInput, TaskOutput, TaskRunner
|
|
21
21
|
class Executor:
|
22
22
|
def __init__(
|
23
23
|
self,
|
24
|
-
|
24
|
+
id: str,
|
25
|
+
version: str,
|
25
26
|
code_path: Path,
|
26
27
|
function_allowlist: Optional[List[FunctionURI]],
|
27
28
|
function_executor_server_factory: FunctionExecutorServerFactory,
|
@@ -48,15 +49,16 @@ class Executor:
|
|
48
49
|
code_path=code_path, base_url=self._base_url, config_path=config_path
|
49
50
|
)
|
50
51
|
self._task_fetcher = TaskFetcher(
|
52
|
+
executor_id=id,
|
53
|
+
executor_version=version,
|
54
|
+
function_allowlist=function_allowlist,
|
51
55
|
protocol=protocol,
|
52
56
|
indexify_server_addr=self._server_addr,
|
53
|
-
executor_id=executor_id,
|
54
|
-
function_allowlist=function_allowlist,
|
55
57
|
config_path=config_path,
|
56
58
|
)
|
57
59
|
self._task_reporter = TaskReporter(
|
58
60
|
base_url=self._base_url,
|
59
|
-
executor_id=
|
61
|
+
executor_id=id,
|
60
62
|
config_path=self._config_path,
|
61
63
|
)
|
62
64
|
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/function_executor.py
RENAMED
@@ -12,6 +12,7 @@ from indexify.function_executor.proto.function_executor_pb2_grpc import (
|
|
12
12
|
)
|
13
13
|
from indexify.utils.http_client import get_httpx_client
|
14
14
|
|
15
|
+
from .health_checker import HealthChecker
|
15
16
|
from .invocation_state_client import InvocationStateClient
|
16
17
|
from .server.function_executor_server import (
|
17
18
|
FUNCTION_EXECUTOR_SERVER_READY_TIMEOUT_SEC,
|
@@ -45,6 +46,7 @@ class FunctionExecutor:
|
|
45
46
|
self._server: Optional[FunctionExecutorServer] = None
|
46
47
|
self._channel: Optional[grpc.aio.Channel] = None
|
47
48
|
self._invocation_state_client: Optional[InvocationStateClient] = None
|
49
|
+
self._health_checker: Optional[HealthChecker] = None
|
48
50
|
self._initialized = False
|
49
51
|
|
50
52
|
async def initialize(
|
@@ -78,6 +80,11 @@ class FunctionExecutor:
|
|
78
80
|
)
|
79
81
|
await self._invocation_state_client.start()
|
80
82
|
|
83
|
+
self._health_checker = HealthChecker(
|
84
|
+
stub=stub,
|
85
|
+
logger=self._logger,
|
86
|
+
)
|
87
|
+
|
81
88
|
self._initialized = True
|
82
89
|
except Exception:
|
83
90
|
await self.destroy()
|
@@ -91,10 +98,21 @@ class FunctionExecutor:
|
|
91
98
|
self._check_initialized()
|
92
99
|
return self._invocation_state_client
|
93
100
|
|
101
|
+
def health_checker(self) -> HealthChecker:
|
102
|
+
self._check_initialized()
|
103
|
+
return self._health_checker
|
104
|
+
|
94
105
|
async def destroy(self):
|
95
106
|
"""Destroys all resources owned by this FunctionExecutor.
|
96
107
|
|
97
108
|
Never raises any exceptions but logs them."""
|
109
|
+
try:
|
110
|
+
if self._health_checker is not None:
|
111
|
+
self._health_checker.stop()
|
112
|
+
self._health_checker = None
|
113
|
+
except Exception as e:
|
114
|
+
self._logger.error("failed to stop HealthChecker", exc_info=e)
|
115
|
+
|
98
116
|
try:
|
99
117
|
if self._invocation_state_client is not None:
|
100
118
|
await self._invocation_state_client.destroy()
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import asyncio
|
2
|
+
from collections.abc import Awaitable, Callable
|
3
|
+
from typing import Any, Optional
|
4
|
+
|
5
|
+
from grpc.aio import AioRpcError
|
6
|
+
|
7
|
+
from indexify.function_executor.proto.function_executor_pb2 import (
|
8
|
+
HealthCheckRequest,
|
9
|
+
HealthCheckResponse,
|
10
|
+
)
|
11
|
+
from indexify.function_executor.proto.function_executor_pb2_grpc import (
|
12
|
+
FunctionExecutorStub,
|
13
|
+
)
|
14
|
+
|
15
|
+
from .server.client_configuration import HEALTH_CHECK_TIMEOUT_SEC
|
16
|
+
|
17
|
+
HEALTH_CHECK_POLL_PERIOD_SEC = 10
|
18
|
+
|
19
|
+
|
20
|
+
class HealthChecker:
|
21
|
+
def __init__(self, stub: FunctionExecutorStub, logger: Any):
|
22
|
+
self._stub: FunctionExecutorStub = stub
|
23
|
+
self._logger: Any = logger.bind(module=__name__)
|
24
|
+
self._health_check_loop_task: Optional[asyncio.Task] = None
|
25
|
+
self._health_check_failed_callback: Optional[Callable[[], Awaitable[None]]] = (
|
26
|
+
None
|
27
|
+
)
|
28
|
+
|
29
|
+
async def check(self) -> bool:
|
30
|
+
"""Runs the health check once and returns the result.
|
31
|
+
|
32
|
+
Does not raise any exceptions."""
|
33
|
+
try:
|
34
|
+
response: HealthCheckResponse = await self._stub.check_health(
|
35
|
+
HealthCheckRequest(), timeout=HEALTH_CHECK_TIMEOUT_SEC
|
36
|
+
)
|
37
|
+
return response.healthy
|
38
|
+
except AioRpcError:
|
39
|
+
return False
|
40
|
+
except Exception as e:
|
41
|
+
self._logger.warning("Got unexpected exception, ignoring", exc_info=e)
|
42
|
+
return False
|
43
|
+
|
44
|
+
def start(self, callback: Callable[[], Awaitable[None]]) -> None:
|
45
|
+
"""Starts periodic health checks.
|
46
|
+
|
47
|
+
The supplied callback is an async function called in the calling thread's
|
48
|
+
event loop when the health check fails. The callback is called only once
|
49
|
+
and then health checks are stopped.
|
50
|
+
|
51
|
+
Without a periodic health check a TCP client socket won't detect a server
|
52
|
+
socket problem (e.g. it's closed due to server crash) because there are no
|
53
|
+
TCP packets floating between them.
|
54
|
+
|
55
|
+
Does not raise any exceptions.
|
56
|
+
"""
|
57
|
+
if self._health_check_loop_task is not None:
|
58
|
+
return
|
59
|
+
|
60
|
+
self._health_check_failed_callback = callback
|
61
|
+
self._health_check_loop_task = asyncio.create_task(self._health_check_loop())
|
62
|
+
|
63
|
+
def stop(self) -> None:
|
64
|
+
"""Stops the periodic health checks.
|
65
|
+
|
66
|
+
Does not raise any exceptions."""
|
67
|
+
if self._health_check_loop_task is None:
|
68
|
+
return
|
69
|
+
|
70
|
+
self._health_check_loop_task.cancel()
|
71
|
+
self._health_check_loop_task = None
|
72
|
+
|
73
|
+
async def _health_check_loop(self) -> None:
|
74
|
+
while True:
|
75
|
+
if not await self.check():
|
76
|
+
break
|
77
|
+
await asyncio.sleep(HEALTH_CHECK_POLL_PERIOD_SEC)
|
78
|
+
|
79
|
+
asyncio.create_task(self._health_check_failed_callback())
|
80
|
+
self._health_check_loop_task = None
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# We send function inputs and outputs over gRPC.
|
2
|
+
# -1 means unlimited. We don't want to limit the size of data customers are using.
|
3
|
+
# The effective max message size in this case is about 1.9 GB, see the max payload test.
|
4
|
+
# This is due to internal hard gRPC limits. When we want to increase the message sizes
|
5
|
+
# we'll have to implement chunking for large messages.
|
6
|
+
_MAX_GRPC_MESSAGE_LENGTH = -1
|
7
|
+
|
8
|
+
# Optimize the channels for low latency connection establishement as we are running on the same host.
|
9
|
+
_RECONNECT_BACKOFF_MS = 100
|
10
|
+
|
11
|
+
GRPC_CHANNEL_OPTIONS = [
|
12
|
+
("grpc.max_receive_message_length", _MAX_GRPC_MESSAGE_LENGTH),
|
13
|
+
("grpc.max_send_message_length", _MAX_GRPC_MESSAGE_LENGTH),
|
14
|
+
("grpc.min_reconnect_backoff_ms", _RECONNECT_BACKOFF_MS),
|
15
|
+
("grpc.max_reconnect_backoff_ms", _RECONNECT_BACKOFF_MS),
|
16
|
+
("grpc.initial_reconnect_backoff_ms", _RECONNECT_BACKOFF_MS),
|
17
|
+
]
|
18
|
+
|
19
|
+
# If a health check takes more than this duration then the server is considered unhealthy.
|
20
|
+
HEALTH_CHECK_TIMEOUT_SEC = 5
|
@@ -22,11 +22,6 @@ class SubprocessFunctionExecutorServerFactory(FunctionExecutorServerFactory):
|
|
22
22
|
async def create(
|
23
23
|
self, config: FunctionExecutorServerConfiguration, logger: Any
|
24
24
|
) -> SubprocessFunctionExecutorServer:
|
25
|
-
if config.image_uri is not None:
|
26
|
-
raise ValueError(
|
27
|
-
"SubprocessFunctionExecutorServerFactory doesn't support container images"
|
28
|
-
)
|
29
|
-
|
30
25
|
logger = logger.bind(module=__name__)
|
31
26
|
port: Optional[int] = None
|
32
27
|
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/single_task_runner.py
RENAMED
@@ -1,6 +1,8 @@
|
|
1
|
+
from collections.abc import Awaitable, Callable
|
1
2
|
from typing import Any, Optional
|
2
3
|
|
3
4
|
import grpc
|
5
|
+
from grpc.aio import AioRpcError
|
4
6
|
|
5
7
|
from indexify.function_executor.proto.function_executor_pb2 import (
|
6
8
|
InitializeRequest,
|
@@ -52,6 +54,12 @@ class SingleTaskRunner:
|
|
52
54
|
if self._state.is_shutdown:
|
53
55
|
raise RuntimeError("Function Executor state is shutting down.")
|
54
56
|
|
57
|
+
# If Function Executor is not healthy then recreate it.
|
58
|
+
if self._state.function_executor is not None:
|
59
|
+
if not await self._state.function_executor.health_checker().check():
|
60
|
+
self._logger.error("Health check failed, destroying FunctionExecutor.")
|
61
|
+
await self._state.destroy_function_executor()
|
62
|
+
|
55
63
|
if self._state.function_executor is None:
|
56
64
|
try:
|
57
65
|
await self._create_function_executor()
|
@@ -110,13 +118,23 @@ class SingleTaskRunner:
|
|
110
118
|
async with _RunningTaskContextManager(
|
111
119
|
invocation_id=self._task_input.task.invocation_id,
|
112
120
|
task_id=self._task_input.task.id,
|
121
|
+
health_check_failed_callback=self._health_check_failed_callback,
|
113
122
|
function_executor_state=self._state,
|
114
123
|
):
|
124
|
+
# If this RPC failed due to customer code crashing the server we won't be
|
125
|
+
# able to detect this. We'll treat this as our own error for now and thus
|
126
|
+
# let the AioRpcError to be raised here.
|
115
127
|
response: RunTaskResponse = await FunctionExecutorStub(channel).run_task(
|
116
128
|
request
|
117
129
|
)
|
118
130
|
return _task_output(task=self._task_input.task, response=response)
|
119
131
|
|
132
|
+
async def _health_check_failed_callback(self):
|
133
|
+
# The Function Executor needs to get recreated on next task run.
|
134
|
+
self._logger.error("Health check failed, destroying FunctionExecutor.")
|
135
|
+
async with self._state.lock:
|
136
|
+
await self._state.destroy_function_executor()
|
137
|
+
|
120
138
|
|
121
139
|
class _RunningTaskContextManager:
|
122
140
|
"""Performs all the actions required before and after running a task."""
|
@@ -125,10 +143,14 @@ class _RunningTaskContextManager:
|
|
125
143
|
self,
|
126
144
|
invocation_id: str,
|
127
145
|
task_id: str,
|
146
|
+
health_check_failed_callback: Callable[[], Awaitable[None]],
|
128
147
|
function_executor_state: FunctionExecutorState,
|
129
148
|
):
|
130
149
|
self._invocation_id: str = invocation_id
|
131
150
|
self._task_id: str = task_id
|
151
|
+
self._health_check_failed_callback: Callable[[], Awaitable[None]] = (
|
152
|
+
health_check_failed_callback
|
153
|
+
)
|
132
154
|
self._state: FunctionExecutorState = function_executor_state
|
133
155
|
|
134
156
|
async def __aenter__(self):
|
@@ -137,6 +159,9 @@ class _RunningTaskContextManager:
|
|
137
159
|
task_id=self._task_id,
|
138
160
|
invocation_id=self._invocation_id,
|
139
161
|
)
|
162
|
+
self._state.function_executor.health_checker().start(
|
163
|
+
self._health_check_failed_callback
|
164
|
+
)
|
140
165
|
# Unlock the state so other tasks can act depending on it.
|
141
166
|
self._state.lock.release()
|
142
167
|
return self
|
@@ -144,9 +169,12 @@ class _RunningTaskContextManager:
|
|
144
169
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
145
170
|
await self._state.lock.acquire()
|
146
171
|
self._state.decrement_running_tasks()
|
147
|
-
|
148
|
-
|
149
|
-
|
172
|
+
# Health check callback could destroy the FunctionExecutor.
|
173
|
+
if self._state.function_executor is not None:
|
174
|
+
self._state.function_executor.invocation_state_client().remove_task_to_invocation_id_entry(
|
175
|
+
task_id=self._task_id
|
176
|
+
)
|
177
|
+
self._state.function_executor.health_checker().stop()
|
150
178
|
|
151
179
|
|
152
180
|
def _task_output(task: Task, response: RunTaskResponse) -> TaskOutput:
|
@@ -16,10 +16,11 @@ class TaskFetcher:
|
|
16
16
|
|
17
17
|
def __init__(
|
18
18
|
self,
|
19
|
-
protocol: str,
|
20
|
-
indexify_server_addr: str,
|
21
19
|
executor_id: str,
|
20
|
+
executor_version: str,
|
22
21
|
function_allowlist: Optional[List[FunctionURI]],
|
22
|
+
protocol: str,
|
23
|
+
indexify_server_addr: str,
|
23
24
|
config_path: Optional[str] = None,
|
24
25
|
):
|
25
26
|
self._protocol: str = protocol
|
@@ -30,7 +31,7 @@ class TaskFetcher:
|
|
30
31
|
probe_info: ProbeInfo = RuntimeProbes().probe()
|
31
32
|
self._executor_metadata: ExecutorMetadata = ExecutorMetadata(
|
32
33
|
id=executor_id,
|
33
|
-
executor_version=
|
34
|
+
executor_version=executor_version,
|
34
35
|
addr="",
|
35
36
|
function_allowlist=function_allowlist,
|
36
37
|
labels=probe_info.labels,
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/handlers/run_function/handler.py
RENAMED
@@ -2,13 +2,12 @@ import io
|
|
2
2
|
import sys
|
3
3
|
import traceback
|
4
4
|
from contextlib import redirect_stderr, redirect_stdout
|
5
|
-
from typing import Any
|
5
|
+
from typing import Any
|
6
6
|
|
7
7
|
from tensorlake.functions_sdk.functions import (
|
8
8
|
FunctionCallResult,
|
9
9
|
GraphInvocationContext,
|
10
10
|
RouterCallResult,
|
11
|
-
TensorlakeCompute,
|
12
11
|
TensorlakeFunctionWrapper,
|
13
12
|
TensorlakeRouter,
|
14
13
|
)
|
@@ -26,15 +25,20 @@ class Handler:
|
|
26
25
|
graph_name: str,
|
27
26
|
graph_version: str,
|
28
27
|
function_name: str,
|
29
|
-
function: Union[TensorlakeCompute, TensorlakeCompute],
|
30
28
|
invocation_state: InvocationState,
|
29
|
+
function_wrapper: TensorlakeFunctionWrapper,
|
31
30
|
logger: Any,
|
32
31
|
):
|
32
|
+
self._invocation_id: str = request.graph_invocation_id
|
33
|
+
self._graph_name: str = graph_name
|
34
|
+
self._graph_version: str = graph_version
|
33
35
|
self._function_name: str = function_name
|
36
|
+
self._invocation_state: InvocationState = invocation_state
|
34
37
|
self._logger = logger.bind(
|
35
38
|
graph_invocation_id=request.graph_invocation_id,
|
36
39
|
task_id=request.task_id,
|
37
40
|
)
|
41
|
+
self._function_wrapper = function_wrapper
|
38
42
|
self._input_loader = FunctionInputsLoader(request)
|
39
43
|
self._response_helper = ResponseHelper(task_id=request.task_id)
|
40
44
|
# TODO: use files for stdout, stderr capturing. This puts a natural and thus reasonable
|
@@ -42,16 +46,6 @@ class Handler:
|
|
42
46
|
self._func_stdout: io.StringIO = io.StringIO()
|
43
47
|
self._func_stderr: io.StringIO = io.StringIO()
|
44
48
|
|
45
|
-
self._function_wrapper: TensorlakeFunctionWrapper = TensorlakeFunctionWrapper(
|
46
|
-
indexify_function=function,
|
47
|
-
context=GraphInvocationContext(
|
48
|
-
invocation_id=request.graph_invocation_id,
|
49
|
-
graph_name=graph_name,
|
50
|
-
graph_version=graph_version,
|
51
|
-
invocation_state=invocation_state,
|
52
|
-
),
|
53
|
-
)
|
54
|
-
|
55
49
|
def run(self) -> RunTaskResponse:
|
56
50
|
"""Runs the task.
|
57
51
|
|
@@ -81,9 +75,15 @@ class Handler:
|
|
81
75
|
)
|
82
76
|
|
83
77
|
def _run_func(self, inputs: FunctionInputs) -> RunTaskResponse:
|
78
|
+
ctx: GraphInvocationContext = GraphInvocationContext(
|
79
|
+
invocation_id=self._invocation_id,
|
80
|
+
graph_name=self._graph_name,
|
81
|
+
graph_version=self._graph_version,
|
82
|
+
invocation_state=self._invocation_state,
|
83
|
+
)
|
84
84
|
if _is_router(self._function_wrapper):
|
85
85
|
result: RouterCallResult = self._function_wrapper.invoke_router(
|
86
|
-
self._function_name, inputs.input
|
86
|
+
ctx, self._function_name, inputs.input
|
87
87
|
)
|
88
88
|
return self._response_helper.router_response(
|
89
89
|
result=result,
|
@@ -92,11 +92,11 @@ class Handler:
|
|
92
92
|
)
|
93
93
|
else:
|
94
94
|
result: FunctionCallResult = self._function_wrapper.invoke_fn_ser(
|
95
|
-
self._function_name, inputs.input, inputs.init_value
|
95
|
+
ctx, self._function_name, inputs.input, inputs.init_value
|
96
96
|
)
|
97
97
|
return self._response_helper.function_response(
|
98
98
|
result=result,
|
99
|
-
is_reducer=
|
99
|
+
is_reducer=_function_is_reducer(self._function_wrapper),
|
100
100
|
stdout=self._func_stdout.getvalue(),
|
101
101
|
stderr=self._func_stderr.getvalue(),
|
102
102
|
)
|
@@ -122,5 +122,5 @@ def _is_router(func_wrapper: TensorlakeFunctionWrapper) -> bool:
|
|
122
122
|
)
|
123
123
|
|
124
124
|
|
125
|
-
def
|
125
|
+
def _function_is_reducer(func_wrapper: TensorlakeFunctionWrapper) -> bool:
|
126
126
|
return func_wrapper.indexify_function.accumulate is not None
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import importlib.metadata
|
2
|
+
import sys
|
3
|
+
from typing import Any, Dict
|
4
|
+
|
5
|
+
|
6
|
+
def info_response_kv_args() -> Dict[str, Any]:
|
7
|
+
sdk_version = importlib.metadata.version("tensorlake")
|
8
|
+
python_version = (
|
9
|
+
f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
10
|
+
)
|
11
|
+
return {
|
12
|
+
"version": "0.1.0",
|
13
|
+
"sdk_version": sdk_version,
|
14
|
+
"sdk_language": "python",
|
15
|
+
"sdk_language_version": python_version,
|
16
|
+
}
|
@@ -10,10 +10,11 @@ import argparse
|
|
10
10
|
|
11
11
|
import structlog
|
12
12
|
|
13
|
+
from .info import info_response_kv_args
|
13
14
|
from .server import Server
|
14
15
|
from .service import Service
|
15
16
|
|
16
|
-
logger = structlog.get_logger(module=__name__)
|
17
|
+
logger = structlog.get_logger(module=__name__).bind(**info_response_kv_args())
|
17
18
|
|
18
19
|
|
19
20
|
def validate_args(args):
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/function_executor.proto
RENAMED
@@ -106,6 +106,28 @@ message RunTaskResponse {
|
|
106
106
|
optional bool success = 7;
|
107
107
|
}
|
108
108
|
|
109
|
+
message HealthCheckRequest {}
|
110
|
+
|
111
|
+
message HealthCheckResponse {
|
112
|
+
optional bool healthy = 1;
|
113
|
+
}
|
114
|
+
|
115
|
+
message InfoRequest {}
|
116
|
+
|
117
|
+
message InfoResponse {
|
118
|
+
// Internal version of this Function Executor.
|
119
|
+
// Semantic versioning schema is used with format 0.0.0.
|
120
|
+
// Used to support migrations.
|
121
|
+
optional string version = 1;
|
122
|
+
// The version of the SDK used in this Function Executor to run customer code.
|
123
|
+
optional string sdk_version = 2;
|
124
|
+
// The language of the SDK. Currently supported values:
|
125
|
+
// - "python"
|
126
|
+
optional string sdk_language = 3;
|
127
|
+
// The version of the SDK language. The language's versioning format is used.
|
128
|
+
optional string sdk_language_version = 4;
|
129
|
+
}
|
130
|
+
|
109
131
|
service FunctionExecutor {
|
110
132
|
// Initializes the Function Executor to run tasks
|
111
133
|
// for a particular function. This method is called only
|
@@ -119,4 +141,8 @@ service FunctionExecutor {
|
|
119
141
|
// Executes the task defined in the request.
|
120
142
|
// Multiple tasks can be running in parallel.
|
121
143
|
rpc run_task(RunTaskRequest) returns (RunTaskResponse);
|
144
|
+
// Health check method to check if the Function Executor is healthy.
|
145
|
+
rpc check_health(HealthCheckRequest) returns (HealthCheckResponse);
|
146
|
+
// Information about this Function Executor.
|
147
|
+
rpc get_info(InfoRequest) returns (InfoResponse);
|
122
148
|
}
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/function_executor_pb2.py
RENAMED
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
|
|
24
24
|
|
25
25
|
|
26
26
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
27
|
-
b'\n8indexify/function_executor/proto/function_executor.proto\x12\x19\x66unction_executor_service"i\n\x10SerializedObject\x12\x0f\n\x05\x62ytes\x18\x01 \x01(\x0cH\x00\x12\x10\n\x06string\x18\x02 \x01(\tH\x00\x12\x19\n\x0c\x63ontent_type\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x06\n\x04\x64\x61taB\x0f\n\r_content_type"\x88\x02\n\x11InitializeRequest\x12\x16\n\tnamespace\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ngraph_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rgraph_version\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rfunction_name\x18\x05 \x01(\tH\x03\x88\x01\x01\x12?\n\x05graph\x18\x07 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x04\x88\x01\x01\x42\x0c\n\n_namespaceB\r\n\x0b_graph_nameB\x10\n\x0e_graph_versionB\x10\n\x0e_function_nameB\x08\n\x06_graph"f\n\x12InitializeResponse\x12\x14\n\x07success\x18\x01 \x01(\x08H\x00\x88\x01\x01\x12\x1b\n\x0e\x63ustomer_error\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\n\n\x08_successB\x11\n\x0f_customer_error"\x80\x01\n\x19SetInvocationStateRequest\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12?\n\x05value\x18\x02 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x01\x88\x01\x01\x42\x06\n\x04_keyB\x08\n\x06_value"\x1c\n\x1aSetInvocationStateResponse"5\n\x19GetInvocationStateRequest\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_key"\x81\x01\n\x1aGetInvocationStateResponse\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12?\n\x05value\x18\x02 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x01\x88\x01\x01\x42\x06\n\x04_keyB\x08\n\x06_value"\xf7\x01\n\x16InvocationStateRequest\x12\x17\n\nrequest_id\x18\x01 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07task_id\x18\x02 \x01(\tH\x02\x88\x01\x01\x12\x43\n\x03set\x18\x03 \x01(\x0b\x32\x34.function_executor_service.SetInvocationStateRequestH\x00\x12\x43\n\x03get\x18\x04 \x01(\x0b\x32\x34.function_executor_service.GetInvocationStateRequestH\x00\x42\t\n\x07requestB\r\n\x0b_request_idB\n\n\x08_task_id"\xfb\x01\n\x17InvocationStateResponse\x12\x17\n\nrequest_id\x18\x01 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07success\x18\x02 \x01(\x08H\x02\x88\x01\x01\x12\x44\n\x03set\x18\x03 \x01(\x0b\x32\x35.function_executor_service.SetInvocationStateResponseH\x00\x12\x44\n\x03get\x18\x04 \x01(\x0b\x32\x35.function_executor_service.GetInvocationStateResponseH\x00\x42\n\n\x08responseB\r\n\x0b_request_idB\n\n\x08_success"N\n\x0e\x46unctionOutput\x12<\n\x07outputs\x18\x01 \x03(\x0b\x32+.function_executor_service.SerializedObject"\x1d\n\x0cRouterOutput\x12\r\n\x05\x65\x64ges\x18\x01 \x03(\t"\xda\x03\n\x0eRunTaskRequest\x12\x16\n\tnamespace\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ngraph_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rgraph_version\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rfunction_name\x18\x04 \x01(\tH\x03\x88\x01\x01\x12 \n\x13graph_invocation_id\x18\x05 \x01(\tH\x04\x88\x01\x01\x12\x14\n\x07task_id\x18\x06 \x01(\tH\x05\x88\x01\x01\x12H\n\x0e\x66unction_input\x18\x07 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x06\x88\x01\x01\x12M\n\x13\x66unction_init_value\x18\x08 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x07\x88\x01\x01\x42\x0c\n\n_namespaceB\r\n\x0b_graph_nameB\x10\n\x0e_graph_versionB\x10\n\x0e_function_nameB\x16\n\x14_graph_invocation_idB\n\n\x08_task_idB\x11\n\x0f_function_inputB\x16\n\x14_function_init_value"\xf1\x02\n\x0fRunTaskResponse\x12\x14\n\x07task_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12G\n\x0f\x66unction_output\x18\x02 \x01(\x0b\x32).function_executor_service.FunctionOutputH\x01\x88\x01\x01\x12\x43\n\rrouter_output\x18\x03 \x01(\x0b\x32\'.function_executor_service.RouterOutputH\x02\x88\x01\x01\x12\x13\n\x06stdout\x18\x04 \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06stderr\x18\x05 \x01(\tH\x04\x88\x01\x01\x12\x17\n\nis_reducer\x18\x06 \x01(\x08H\x05\x88\x01\x01\x12\x14\n\x07success\x18\x07 \x01(\x08H\x06\x88\x01\x01\x42\n\n\x08_task_idB\x12\n\x10_function_outputB\x10\n\x0e_router_outputB\t\n\x07_stdoutB\t\n\x07_stderrB\r\n\x0b_is_reducerB\n\n\
|
27
|
+
b'\n8indexify/function_executor/proto/function_executor.proto\x12\x19\x66unction_executor_service"i\n\x10SerializedObject\x12\x0f\n\x05\x62ytes\x18\x01 \x01(\x0cH\x00\x12\x10\n\x06string\x18\x02 \x01(\tH\x00\x12\x19\n\x0c\x63ontent_type\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x06\n\x04\x64\x61taB\x0f\n\r_content_type"\x88\x02\n\x11InitializeRequest\x12\x16\n\tnamespace\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ngraph_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rgraph_version\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rfunction_name\x18\x05 \x01(\tH\x03\x88\x01\x01\x12?\n\x05graph\x18\x07 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x04\x88\x01\x01\x42\x0c\n\n_namespaceB\r\n\x0b_graph_nameB\x10\n\x0e_graph_versionB\x10\n\x0e_function_nameB\x08\n\x06_graph"f\n\x12InitializeResponse\x12\x14\n\x07success\x18\x01 \x01(\x08H\x00\x88\x01\x01\x12\x1b\n\x0e\x63ustomer_error\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\n\n\x08_successB\x11\n\x0f_customer_error"\x80\x01\n\x19SetInvocationStateRequest\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12?\n\x05value\x18\x02 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x01\x88\x01\x01\x42\x06\n\x04_keyB\x08\n\x06_value"\x1c\n\x1aSetInvocationStateResponse"5\n\x19GetInvocationStateRequest\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_key"\x81\x01\n\x1aGetInvocationStateResponse\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12?\n\x05value\x18\x02 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x01\x88\x01\x01\x42\x06\n\x04_keyB\x08\n\x06_value"\xf7\x01\n\x16InvocationStateRequest\x12\x17\n\nrequest_id\x18\x01 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07task_id\x18\x02 \x01(\tH\x02\x88\x01\x01\x12\x43\n\x03set\x18\x03 \x01(\x0b\x32\x34.function_executor_service.SetInvocationStateRequestH\x00\x12\x43\n\x03get\x18\x04 \x01(\x0b\x32\x34.function_executor_service.GetInvocationStateRequestH\x00\x42\t\n\x07requestB\r\n\x0b_request_idB\n\n\x08_task_id"\xfb\x01\n\x17InvocationStateResponse\x12\x17\n\nrequest_id\x18\x01 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07success\x18\x02 \x01(\x08H\x02\x88\x01\x01\x12\x44\n\x03set\x18\x03 \x01(\x0b\x32\x35.function_executor_service.SetInvocationStateResponseH\x00\x12\x44\n\x03get\x18\x04 \x01(\x0b\x32\x35.function_executor_service.GetInvocationStateResponseH\x00\x42\n\n\x08responseB\r\n\x0b_request_idB\n\n\x08_success"N\n\x0e\x46unctionOutput\x12<\n\x07outputs\x18\x01 \x03(\x0b\x32+.function_executor_service.SerializedObject"\x1d\n\x0cRouterOutput\x12\r\n\x05\x65\x64ges\x18\x01 \x03(\t"\xda\x03\n\x0eRunTaskRequest\x12\x16\n\tnamespace\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ngraph_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rgraph_version\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rfunction_name\x18\x04 \x01(\tH\x03\x88\x01\x01\x12 \n\x13graph_invocation_id\x18\x05 \x01(\tH\x04\x88\x01\x01\x12\x14\n\x07task_id\x18\x06 \x01(\tH\x05\x88\x01\x01\x12H\n\x0e\x66unction_input\x18\x07 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x06\x88\x01\x01\x12M\n\x13\x66unction_init_value\x18\x08 \x01(\x0b\x32+.function_executor_service.SerializedObjectH\x07\x88\x01\x01\x42\x0c\n\n_namespaceB\r\n\x0b_graph_nameB\x10\n\x0e_graph_versionB\x10\n\x0e_function_nameB\x16\n\x14_graph_invocation_idB\n\n\x08_task_idB\x11\n\x0f_function_inputB\x16\n\x14_function_init_value"\xf1\x02\n\x0fRunTaskResponse\x12\x14\n\x07task_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12G\n\x0f\x66unction_output\x18\x02 \x01(\x0b\x32).function_executor_service.FunctionOutputH\x01\x88\x01\x01\x12\x43\n\rrouter_output\x18\x03 \x01(\x0b\x32\'.function_executor_service.RouterOutputH\x02\x88\x01\x01\x12\x13\n\x06stdout\x18\x04 \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06stderr\x18\x05 \x01(\tH\x04\x88\x01\x01\x12\x17\n\nis_reducer\x18\x06 \x01(\x08H\x05\x88\x01\x01\x12\x14\n\x07success\x18\x07 \x01(\x08H\x06\x88\x01\x01\x42\n\n\x08_task_idB\x12\n\x10_function_outputB\x10\n\x0e_router_outputB\t\n\x07_stdoutB\t\n\x07_stderrB\r\n\x0b_is_reducerB\n\n\x08_success"\x14\n\x12HealthCheckRequest"7\n\x13HealthCheckResponse\x12\x14\n\x07healthy\x18\x01 \x01(\x08H\x00\x88\x01\x01\x42\n\n\x08_healthy"\r\n\x0bInfoRequest"\xc2\x01\n\x0cInfoResponse\x12\x14\n\x07version\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0bsdk_version\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x19\n\x0csdk_language\x18\x03 \x01(\tH\x02\x88\x01\x01\x12!\n\x14sdk_language_version\x18\x04 \x01(\tH\x03\x88\x01\x01\x42\n\n\x08_versionB\x0e\n\x0c_sdk_versionB\x0f\n\r_sdk_languageB\x17\n\x15_sdk_language_version2\xbe\x04\n\x10\x46unctionExecutor\x12i\n\ninitialize\x12,.function_executor_service.InitializeRequest\x1a-.function_executor_service.InitializeResponse\x12\x8f\x01\n"initialize_invocation_state_server\x12\x32.function_executor_service.InvocationStateResponse\x1a\x31.function_executor_service.InvocationStateRequest(\x01\x30\x01\x12\x61\n\x08run_task\x12).function_executor_service.RunTaskRequest\x1a*.function_executor_service.RunTaskResponse\x12m\n\x0c\x63heck_health\x12-.function_executor_service.HealthCheckRequest\x1a..function_executor_service.HealthCheckResponse\x12[\n\x08get_info\x12&.function_executor_service.InfoRequest\x1a\'.function_executor_service.InfoResponseb\x06proto3'
|
28
28
|
)
|
29
29
|
|
30
30
|
_globals = globals()
|
@@ -60,6 +60,14 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
60
60
|
_globals["_RUNTASKREQUEST"]._serialized_end = 2003
|
61
61
|
_globals["_RUNTASKRESPONSE"]._serialized_start = 2006
|
62
62
|
_globals["_RUNTASKRESPONSE"]._serialized_end = 2375
|
63
|
-
_globals["
|
64
|
-
_globals["
|
63
|
+
_globals["_HEALTHCHECKREQUEST"]._serialized_start = 2377
|
64
|
+
_globals["_HEALTHCHECKREQUEST"]._serialized_end = 2397
|
65
|
+
_globals["_HEALTHCHECKRESPONSE"]._serialized_start = 2399
|
66
|
+
_globals["_HEALTHCHECKRESPONSE"]._serialized_end = 2454
|
67
|
+
_globals["_INFOREQUEST"]._serialized_start = 2456
|
68
|
+
_globals["_INFOREQUEST"]._serialized_end = 2469
|
69
|
+
_globals["_INFORESPONSE"]._serialized_start = 2472
|
70
|
+
_globals["_INFORESPONSE"]._serialized_end = 2666
|
71
|
+
_globals["_FUNCTIONEXECUTOR"]._serialized_start = 2669
|
72
|
+
_globals["_FUNCTIONEXECUTOR"]._serialized_end = 3243
|
65
73
|
# @@protoc_insertion_point(module_scope)
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/function_executor_pb2.pyi
RENAMED
@@ -213,3 +213,35 @@ class RunTaskResponse(_message.Message):
|
|
213
213
|
is_reducer: bool = ...,
|
214
214
|
success: bool = ...,
|
215
215
|
) -> None: ...
|
216
|
+
|
217
|
+
class HealthCheckRequest(_message.Message):
|
218
|
+
__slots__ = ()
|
219
|
+
def __init__(self) -> None: ...
|
220
|
+
|
221
|
+
class HealthCheckResponse(_message.Message):
|
222
|
+
__slots__ = ("healthy",)
|
223
|
+
HEALTHY_FIELD_NUMBER: _ClassVar[int]
|
224
|
+
healthy: bool
|
225
|
+
def __init__(self, healthy: bool = ...) -> None: ...
|
226
|
+
|
227
|
+
class InfoRequest(_message.Message):
|
228
|
+
__slots__ = ()
|
229
|
+
def __init__(self) -> None: ...
|
230
|
+
|
231
|
+
class InfoResponse(_message.Message):
|
232
|
+
__slots__ = ("version", "sdk_version", "sdk_language", "sdk_language_version")
|
233
|
+
VERSION_FIELD_NUMBER: _ClassVar[int]
|
234
|
+
SDK_VERSION_FIELD_NUMBER: _ClassVar[int]
|
235
|
+
SDK_LANGUAGE_FIELD_NUMBER: _ClassVar[int]
|
236
|
+
SDK_LANGUAGE_VERSION_FIELD_NUMBER: _ClassVar[int]
|
237
|
+
version: str
|
238
|
+
sdk_version: str
|
239
|
+
sdk_language: str
|
240
|
+
sdk_language_version: str
|
241
|
+
def __init__(
|
242
|
+
self,
|
243
|
+
version: _Optional[str] = ...,
|
244
|
+
sdk_version: _Optional[str] = ...,
|
245
|
+
sdk_language: _Optional[str] = ...,
|
246
|
+
sdk_language_version: _Optional[str] = ...,
|
247
|
+
) -> None: ...
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/proto/function_executor_pb2_grpc.py
RENAMED
@@ -58,6 +58,18 @@ class FunctionExecutorStub(object):
|
|
58
58
|
response_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.RunTaskResponse.FromString,
|
59
59
|
_registered_method=True,
|
60
60
|
)
|
61
|
+
self.check_health = channel.unary_unary(
|
62
|
+
"/function_executor_service.FunctionExecutor/check_health",
|
63
|
+
request_serializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckRequest.SerializeToString,
|
64
|
+
response_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckResponse.FromString,
|
65
|
+
_registered_method=True,
|
66
|
+
)
|
67
|
+
self.get_info = channel.unary_unary(
|
68
|
+
"/function_executor_service.FunctionExecutor/get_info",
|
69
|
+
request_serializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoRequest.SerializeToString,
|
70
|
+
response_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoResponse.FromString,
|
71
|
+
_registered_method=True,
|
72
|
+
)
|
61
73
|
|
62
74
|
|
63
75
|
class FunctionExecutorServicer(object):
|
@@ -90,6 +102,18 @@ class FunctionExecutorServicer(object):
|
|
90
102
|
context.set_details("Method not implemented!")
|
91
103
|
raise NotImplementedError("Method not implemented!")
|
92
104
|
|
105
|
+
def check_health(self, request, context):
|
106
|
+
"""Health check method to check if the Function Executor is healthy."""
|
107
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
108
|
+
context.set_details("Method not implemented!")
|
109
|
+
raise NotImplementedError("Method not implemented!")
|
110
|
+
|
111
|
+
def get_info(self, request, context):
|
112
|
+
"""Information about this Function Executor."""
|
113
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
114
|
+
context.set_details("Method not implemented!")
|
115
|
+
raise NotImplementedError("Method not implemented!")
|
116
|
+
|
93
117
|
|
94
118
|
def add_FunctionExecutorServicer_to_server(servicer, server):
|
95
119
|
rpc_method_handlers = {
|
@@ -108,6 +132,16 @@ def add_FunctionExecutorServicer_to_server(servicer, server):
|
|
108
132
|
request_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.RunTaskRequest.FromString,
|
109
133
|
response_serializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.RunTaskResponse.SerializeToString,
|
110
134
|
),
|
135
|
+
"check_health": grpc.unary_unary_rpc_method_handler(
|
136
|
+
servicer.check_health,
|
137
|
+
request_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckRequest.FromString,
|
138
|
+
response_serializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckResponse.SerializeToString,
|
139
|
+
),
|
140
|
+
"get_info": grpc.unary_unary_rpc_method_handler(
|
141
|
+
servicer.get_info,
|
142
|
+
request_deserializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoRequest.FromString,
|
143
|
+
response_serializer=indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoResponse.SerializeToString,
|
144
|
+
),
|
111
145
|
}
|
112
146
|
generic_handler = grpc.method_handlers_generic_handler(
|
113
147
|
"function_executor_service.FunctionExecutor", rpc_method_handlers
|
@@ -211,3 +245,63 @@ class FunctionExecutor(object):
|
|
211
245
|
metadata,
|
212
246
|
_registered_method=True,
|
213
247
|
)
|
248
|
+
|
249
|
+
@staticmethod
|
250
|
+
def check_health(
|
251
|
+
request,
|
252
|
+
target,
|
253
|
+
options=(),
|
254
|
+
channel_credentials=None,
|
255
|
+
call_credentials=None,
|
256
|
+
insecure=False,
|
257
|
+
compression=None,
|
258
|
+
wait_for_ready=None,
|
259
|
+
timeout=None,
|
260
|
+
metadata=None,
|
261
|
+
):
|
262
|
+
return grpc.experimental.unary_unary(
|
263
|
+
request,
|
264
|
+
target,
|
265
|
+
"/function_executor_service.FunctionExecutor/check_health",
|
266
|
+
indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckRequest.SerializeToString,
|
267
|
+
indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.HealthCheckResponse.FromString,
|
268
|
+
options,
|
269
|
+
channel_credentials,
|
270
|
+
insecure,
|
271
|
+
call_credentials,
|
272
|
+
compression,
|
273
|
+
wait_for_ready,
|
274
|
+
timeout,
|
275
|
+
metadata,
|
276
|
+
_registered_method=True,
|
277
|
+
)
|
278
|
+
|
279
|
+
@staticmethod
|
280
|
+
def get_info(
|
281
|
+
request,
|
282
|
+
target,
|
283
|
+
options=(),
|
284
|
+
channel_credentials=None,
|
285
|
+
call_credentials=None,
|
286
|
+
insecure=False,
|
287
|
+
compression=None,
|
288
|
+
wait_for_ready=None,
|
289
|
+
timeout=None,
|
290
|
+
metadata=None,
|
291
|
+
):
|
292
|
+
return grpc.experimental.unary_unary(
|
293
|
+
request,
|
294
|
+
target,
|
295
|
+
"/function_executor_service.FunctionExecutor/get_info",
|
296
|
+
indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoRequest.SerializeToString,
|
297
|
+
indexify_dot_function__executor_dot_proto_dot_function__executor__pb2.InfoResponse.FromString,
|
298
|
+
options,
|
299
|
+
channel_credentials,
|
300
|
+
insecure,
|
301
|
+
call_credentials,
|
302
|
+
compression,
|
303
|
+
wait_for_ready,
|
304
|
+
timeout,
|
305
|
+
metadata,
|
306
|
+
_registered_method=True,
|
307
|
+
)
|
@@ -2,8 +2,8 @@ from concurrent.futures import ThreadPoolExecutor
|
|
2
2
|
|
3
3
|
import grpc
|
4
4
|
|
5
|
-
from .proto.configuration import GRPC_SERVER_OPTIONS
|
6
5
|
from .proto.function_executor_pb2_grpc import add_FunctionExecutorServicer_to_server
|
6
|
+
from .proto.server_configuration import GRPC_SERVER_OPTIONS
|
7
7
|
from .service import Service
|
8
8
|
|
9
9
|
# Temporary limit until we have a better way to control this.
|
@@ -1,18 +1,23 @@
|
|
1
|
-
from typing import Iterator, Optional
|
1
|
+
from typing import Iterator, Optional
|
2
2
|
|
3
3
|
import grpc
|
4
4
|
import structlog
|
5
|
-
from tensorlake.functions_sdk.functions import
|
5
|
+
from tensorlake.functions_sdk.functions import TensorlakeFunctionWrapper
|
6
6
|
from tensorlake.functions_sdk.object_serializer import get_serializer
|
7
7
|
|
8
8
|
from .handlers.run_function.handler import Handler as RunTaskHandler
|
9
9
|
from .handlers.run_function.request_validator import (
|
10
10
|
RequestValidator as RunTaskRequestValidator,
|
11
11
|
)
|
12
|
+
from .info import info_response_kv_args
|
12
13
|
from .initialize_request_validator import InitializeRequestValidator
|
13
14
|
from .invocation_state.invocation_state_proxy_server import InvocationStateProxyServer
|
14
15
|
from .invocation_state.proxied_invocation_state import ProxiedInvocationState
|
15
16
|
from .proto.function_executor_pb2 import (
|
17
|
+
HealthCheckRequest,
|
18
|
+
HealthCheckResponse,
|
19
|
+
InfoRequest,
|
20
|
+
InfoResponse,
|
16
21
|
InitializeRequest,
|
17
22
|
InitializeResponse,
|
18
23
|
InvocationStateResponse,
|
@@ -24,12 +29,14 @@ from .proto.function_executor_pb2_grpc import FunctionExecutorServicer
|
|
24
29
|
|
25
30
|
class Service(FunctionExecutorServicer):
|
26
31
|
def __init__(self):
|
27
|
-
self._logger = structlog.get_logger(module=__name__)
|
32
|
+
self._logger = structlog.get_logger(module=__name__).bind(
|
33
|
+
**info_response_kv_args()
|
34
|
+
)
|
28
35
|
self._namespace: Optional[str] = None
|
29
36
|
self._graph_name: Optional[str] = None
|
30
37
|
self._graph_version: Optional[str] = None
|
31
38
|
self._function_name: Optional[str] = None
|
32
|
-
self.
|
39
|
+
self._function_wrapper: Optional[TensorlakeFunctionWrapper] = None
|
33
40
|
self._invocation_state_proxy_server: Optional[InvocationStateProxyServer] = None
|
34
41
|
|
35
42
|
def initialize(
|
@@ -59,8 +66,10 @@ class Service(FunctionExecutorServicer):
|
|
59
66
|
try:
|
60
67
|
# Process user controlled input in a try-except block to not treat errors here as our
|
61
68
|
# internal platform errors.
|
69
|
+
# TODO: capture stdout and stderr and report exceptions the same way as when we run a task.
|
62
70
|
graph = graph_serializer.deserialize(request.graph.bytes)
|
63
|
-
|
71
|
+
function = graph_serializer.deserialize(graph[request.function_name])
|
72
|
+
self._function_wrapper = TensorlakeFunctionWrapper(function)
|
64
73
|
except Exception as e:
|
65
74
|
return InitializeResponse(success=False, customer_error=str(e))
|
66
75
|
|
@@ -93,10 +102,10 @@ class Service(FunctionExecutorServicer):
|
|
93
102
|
graph_name=self._graph_name,
|
94
103
|
graph_version=self._graph_version,
|
95
104
|
function_name=self._function_name,
|
96
|
-
function=self._function,
|
97
105
|
invocation_state=ProxiedInvocationState(
|
98
106
|
request.task_id, self._invocation_state_proxy_server
|
99
107
|
),
|
108
|
+
function_wrapper=self._function_wrapper,
|
100
109
|
logger=self._logger,
|
101
110
|
).run()
|
102
111
|
|
@@ -120,3 +129,17 @@ class Service(FunctionExecutorServicer):
|
|
120
129
|
raise ValueError(
|
121
130
|
f"This Function Executor is not initialized for this function_name {request.function_name}"
|
122
131
|
)
|
132
|
+
|
133
|
+
def check_health(
|
134
|
+
self, request: HealthCheckRequest, context: grpc.ServicerContext
|
135
|
+
) -> HealthCheckResponse:
|
136
|
+
# This health check validates that the Server:
|
137
|
+
# - Has its process alive (not exited).
|
138
|
+
# - Didn't exhaust its thread pool.
|
139
|
+
# - Is able to communicate over its server socket.
|
140
|
+
return HealthCheckResponse(healthy=True)
|
141
|
+
|
142
|
+
def get_info(
|
143
|
+
self, request: InfoRequest, context: grpc.ServicerContext
|
144
|
+
) -> InfoResponse:
|
145
|
+
return InfoResponse(**info_response_kv_args())
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/function_executor_state.py
RENAMED
File without changes
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/executor/function_executor/invocation_state_client.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{indexify-0.3.3 → indexify-0.3.5}/src/indexify/function_executor/initialize_request_validator.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|