indexify 0.4.5__tar.gz → 0.4.7__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.4.5 → indexify-0.4.7}/PKG-INFO +2 -2
- {indexify-0.4.5 → indexify-0.4.7}/pyproject.toml +2 -2
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/function_executor.py +30 -25
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/__init__.py +7 -4
- indexify-0.4.7/src/indexify/executor/function_executor_controller/create_function_executor.py +256 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/destroy_function_executor.py +1 -1
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/events.py +10 -14
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/function_executor_controller.py +108 -66
- indexify-0.4.7/src/indexify/executor/function_executor_controller/function_executor_startup_output.py +21 -0
- indexify-0.4.7/src/indexify/executor/function_executor_controller/loggers.py +107 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/message_validators.py +16 -1
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/prepare_task.py +3 -3
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/run_task.py +19 -27
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/task_info.py +2 -3
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/task_output.py +12 -24
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/upload_task_output.py +7 -7
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/state_reconciler.py +5 -33
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/state_reporter.py +46 -56
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/proto/executor_api.proto +34 -17
- indexify-0.4.7/src/indexify/proto/executor_api_pb2.py +90 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/proto/executor_api_pb2.pyi +50 -8
- indexify-0.4.5/src/indexify/executor/function_executor_controller/create_function_executor.py +0 -158
- indexify-0.4.5/src/indexify/executor/function_executor_controller/loggers.py +0 -57
- indexify-0.4.5/src/indexify/proto/executor_api_pb2.py +0 -86
- {indexify-0.4.5 → indexify-0.4.7}/README.md +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/cli/__init__.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/cli/build_image.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/cli/deploy.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/cli/executor.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/README.md +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/blob_store/blob_store.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/blob_store/local_fs_blob_store.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/blob_store/metrics/blob_store.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/blob_store/s3_blob_store.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/channel_manager.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/executor.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_allowlist.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/health_checker.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/invocation_state_client.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/metrics/function_executor.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/metrics/health_checker.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/metrics/invocation_state_client.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/server/client_configuration.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/server/function_executor_server.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/server/function_executor_server_factory.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/server/subprocess_function_executor_server.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/completed_task_metrics.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/debug_event_loop.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/downloads.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/metrics/completed_task_metrics.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/metrics/downloads.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/metrics/function_executor_controller.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/metrics/run_task.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/metrics/upload_task_output.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/host_resources/host_resources.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/host_resources/nvidia_gpu.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/host_resources/nvidia_gpu_allocator.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/metrics/channel_manager.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/metrics/executor.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/metrics/state_reconciler.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/metrics/state_reporter.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/monitoring/handler.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/monitoring/health_check_handler.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/monitoring/health_checker/generic_health_checker.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/monitoring/health_checker/health_checker.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/monitoring/metrics.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/monitoring/prometheus_metrics_handler.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/monitoring/server.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/monitoring/startup_probe_handler.py +0 -0
- {indexify-0.4.5 → indexify-0.4.7}/src/indexify/proto/executor_api_pb2_grpc.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: indexify
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.7
|
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,7 +17,7 @@ Requires-Dist: aiohttp (>=3.11.0,<4.0.0)
|
|
17
17
|
Requires-Dist: boto3 (>=1.37.30,<2.0.0)
|
18
18
|
Requires-Dist: prometheus-client (>=0.21.1,<0.22.0)
|
19
19
|
Requires-Dist: psutil (>=7.0.0,<8.0.0)
|
20
|
-
Requires-Dist: tensorlake (==0.
|
20
|
+
Requires-Dist: tensorlake (==0.2.6)
|
21
21
|
Project-URL: Repository, https://github.com/tensorlakeai/indexify
|
22
22
|
Description-Content-Type: text/markdown
|
23
23
|
|
@@ -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.4.
|
4
|
+
version = "0.4.7"
|
5
5
|
description = "Open Source Indexify components and helper tools"
|
6
6
|
authors = ["Tensorlake Inc. <support@tensorlake.ai>"]
|
7
7
|
license = "Apache 2.0"
|
@@ -25,7 +25,7 @@ prometheus-client = "^0.21.1"
|
|
25
25
|
psutil = "^7.0.0"
|
26
26
|
# Adds function-executor binary, utils lib, sdk used in indexify-cli commands.
|
27
27
|
# We need to specify the tensorlake version exactly because pip install doesn't respect poetry.lock files.
|
28
|
-
tensorlake = "0.
|
28
|
+
tensorlake = "0.2.6"
|
29
29
|
# Uncomment the next line to use local tensorlake package (only for development!)
|
30
30
|
# tensorlake = { path = "../tensorlake", develop = true }
|
31
31
|
# pydantic is provided by tensorlake
|
{indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor/function_executor.py
RENAMED
@@ -1,4 +1,6 @@
|
|
1
1
|
import asyncio
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from enum import Enum
|
2
4
|
from typing import Any, Optional
|
3
5
|
|
4
6
|
import grpc
|
@@ -56,12 +58,19 @@ from .server.function_executor_server_factory import (
|
|
56
58
|
)
|
57
59
|
|
58
60
|
|
59
|
-
class
|
60
|
-
|
61
|
+
class FunctionExecutorInitializationError(Enum):
|
62
|
+
FUNCTION_TIMEOUT = 1
|
63
|
+
FUNCTION_ERROR = 2
|
61
64
|
|
62
65
|
|
63
|
-
|
64
|
-
|
66
|
+
@dataclass
|
67
|
+
class FunctionExecutorInitializationResult:
|
68
|
+
"""Result of FunctionExecutor initialization."""
|
69
|
+
|
70
|
+
# None error means success.
|
71
|
+
error: Optional[FunctionExecutorInitializationError] = None
|
72
|
+
stdout: Optional[str] = None
|
73
|
+
stderr: Optional[str] = None
|
65
74
|
|
66
75
|
|
67
76
|
class FunctionExecutor:
|
@@ -83,7 +92,6 @@ class FunctionExecutor:
|
|
83
92
|
self._channel: Optional[grpc.aio.Channel] = None
|
84
93
|
self._invocation_state_client: Optional[InvocationStateClient] = None
|
85
94
|
self._health_checker: Optional[HealthChecker] = None
|
86
|
-
self._initialized = False
|
87
95
|
metric_function_executors_count.inc()
|
88
96
|
|
89
97
|
async def initialize(
|
@@ -93,10 +101,9 @@ class FunctionExecutor:
|
|
93
101
|
base_url: str,
|
94
102
|
config_path: Optional[str],
|
95
103
|
customer_code_timeout_sec: Optional[float] = None,
|
96
|
-
):
|
104
|
+
) -> FunctionExecutorInitializationResult:
|
97
105
|
"""Creates and initializes a FunctionExecutorServer and all resources associated with it.
|
98
106
|
|
99
|
-
Raises FunctionError if the server failed to initialize due to an error in customer owned code or data.
|
100
107
|
Raises an Exception if an internal error occured."""
|
101
108
|
try:
|
102
109
|
with (
|
@@ -108,9 +115,6 @@ class FunctionExecutor:
|
|
108
115
|
await self._establish_channel()
|
109
116
|
stub: FunctionExecutorStub = FunctionExecutorStub(self._channel)
|
110
117
|
await _collect_server_info(stub)
|
111
|
-
await _initialize_server(
|
112
|
-
stub, initialize_request, customer_code_timeout_sec
|
113
|
-
)
|
114
118
|
await self._create_invocation_state_client(
|
115
119
|
stub=stub,
|
116
120
|
base_url=base_url,
|
@@ -118,21 +122,21 @@ class FunctionExecutor:
|
|
118
122
|
initialize_request=initialize_request,
|
119
123
|
)
|
120
124
|
await self._create_health_checker(self._channel, stub)
|
121
|
-
|
125
|
+
|
126
|
+
return await _initialize_server(
|
127
|
+
stub, initialize_request, customer_code_timeout_sec
|
128
|
+
)
|
122
129
|
except Exception:
|
123
130
|
await self.destroy()
|
124
131
|
raise
|
125
132
|
|
126
133
|
def channel(self) -> grpc.aio.Channel:
|
127
|
-
self._check_initialized()
|
128
134
|
return self._channel
|
129
135
|
|
130
136
|
def invocation_state_client(self) -> InvocationStateClient:
|
131
|
-
self._check_initialized()
|
132
137
|
return self._invocation_state_client
|
133
138
|
|
134
139
|
def health_checker(self) -> HealthChecker:
|
135
|
-
self._check_initialized()
|
136
140
|
return self._health_checker
|
137
141
|
|
138
142
|
async def destroy(self):
|
@@ -158,10 +162,6 @@ class FunctionExecutor:
|
|
158
162
|
exc_info=e,
|
159
163
|
)
|
160
164
|
|
161
|
-
def _check_initialized(self) -> None:
|
162
|
-
if not self._initialized:
|
163
|
-
raise RuntimeError("FunctionExecutor is not initialized")
|
164
|
-
|
165
165
|
async def _create_server(self, config: FunctionExecutorServerConfiguration) -> None:
|
166
166
|
with (
|
167
167
|
metric_create_server_errors.count_exceptions(),
|
@@ -305,7 +305,7 @@ async def _initialize_server(
|
|
305
305
|
stub: FunctionExecutorStub,
|
306
306
|
initialize_request: InitializeRequest,
|
307
307
|
customer_code_timeout_sec: Optional[float],
|
308
|
-
) ->
|
308
|
+
) -> FunctionExecutorInitializationResult:
|
309
309
|
with (
|
310
310
|
metric_initialize_rpc_errors.count_exceptions(),
|
311
311
|
metric_initialize_rpc_latency.time(),
|
@@ -315,15 +315,20 @@ async def _initialize_server(
|
|
315
315
|
initialize_request,
|
316
316
|
timeout=customer_code_timeout_sec,
|
317
317
|
)
|
318
|
+
# TODO: set real stdout and stderr when their proper capturing on FE initialization is implemented.
|
318
319
|
if initialize_response.success:
|
319
|
-
return
|
320
|
-
|
321
|
-
|
320
|
+
return FunctionExecutorInitializationResult()
|
321
|
+
elif initialize_response.HasField("customer_error"):
|
322
|
+
return FunctionExecutorInitializationResult(
|
323
|
+
error=FunctionExecutorInitializationError.FUNCTION_ERROR,
|
324
|
+
stderr=initialize_response.customer_error,
|
325
|
+
)
|
322
326
|
else:
|
323
327
|
raise Exception("initialize RPC failed at function executor server")
|
324
328
|
except grpc.aio.AioRpcError as e:
|
325
329
|
if e.code() == grpc.StatusCode.DEADLINE_EXCEEDED:
|
326
|
-
|
327
|
-
|
328
|
-
|
330
|
+
return FunctionExecutorInitializationResult(
|
331
|
+
error=FunctionExecutorInitializationError.FUNCTION_TIMEOUT,
|
332
|
+
stderr=f"Function initialization exceeded its configured timeout of {customer_code_timeout_sec:.3f} sec.",
|
333
|
+
)
|
329
334
|
raise
|
{indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/__init__.py
RENAMED
@@ -1,13 +1,16 @@
|
|
1
1
|
from .function_executor_controller import FunctionExecutorController
|
2
|
-
from .loggers import function_executor_logger,
|
3
|
-
from .message_validators import
|
2
|
+
from .loggers import function_executor_logger, task_allocation_logger
|
3
|
+
from .message_validators import (
|
4
|
+
validate_function_executor_description,
|
5
|
+
validate_task_allocation,
|
6
|
+
)
|
4
7
|
from .task_output import TaskOutput
|
5
8
|
|
6
9
|
__all__ = [
|
7
10
|
"function_executor_logger",
|
8
|
-
"
|
11
|
+
"task_allocation_logger",
|
9
12
|
"validate_function_executor_description",
|
10
|
-
"
|
13
|
+
"validate_task_allocation",
|
11
14
|
"FunctionExecutorController",
|
12
15
|
"TaskOutput",
|
13
16
|
]
|
@@ -0,0 +1,256 @@
|
|
1
|
+
import asyncio
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Any, Optional, Tuple
|
4
|
+
|
5
|
+
from tensorlake.function_executor.proto.function_executor_pb2 import (
|
6
|
+
InitializeRequest,
|
7
|
+
SerializedObject,
|
8
|
+
)
|
9
|
+
|
10
|
+
from indexify.executor.blob_store.blob_store import BLOBStore
|
11
|
+
from indexify.executor.function_executor.function_executor import (
|
12
|
+
FunctionExecutor,
|
13
|
+
FunctionExecutorInitializationError,
|
14
|
+
FunctionExecutorInitializationResult,
|
15
|
+
)
|
16
|
+
from indexify.executor.function_executor.server.function_executor_server_factory import (
|
17
|
+
FunctionExecutorServerConfiguration,
|
18
|
+
FunctionExecutorServerFactory,
|
19
|
+
)
|
20
|
+
from indexify.proto.executor_api_pb2 import (
|
21
|
+
DataPayload,
|
22
|
+
DataPayloadEncoding,
|
23
|
+
FunctionExecutorDescription,
|
24
|
+
FunctionExecutorTerminationReason,
|
25
|
+
)
|
26
|
+
|
27
|
+
from .downloads import download_graph
|
28
|
+
from .events import FunctionExecutorCreated
|
29
|
+
from .function_executor_startup_output import FunctionExecutorStartupOutput
|
30
|
+
from .upload_task_output import compute_hash
|
31
|
+
|
32
|
+
|
33
|
+
async def create_function_executor(
|
34
|
+
function_executor_description: FunctionExecutorDescription,
|
35
|
+
function_executor_server_factory: FunctionExecutorServerFactory,
|
36
|
+
blob_store: BLOBStore,
|
37
|
+
executor_id: str,
|
38
|
+
base_url: str,
|
39
|
+
config_path: str,
|
40
|
+
cache_path: Path,
|
41
|
+
logger: Any,
|
42
|
+
) -> FunctionExecutorCreated:
|
43
|
+
"""Creates a function executor.
|
44
|
+
|
45
|
+
Doesn't raise any exceptions.
|
46
|
+
"""
|
47
|
+
logger = logger.bind(module=__name__)
|
48
|
+
try:
|
49
|
+
function_executor, result = await _create_function_executor(
|
50
|
+
function_executor_description=function_executor_description,
|
51
|
+
function_executor_server_factory=function_executor_server_factory,
|
52
|
+
blob_store=blob_store,
|
53
|
+
executor_id=executor_id,
|
54
|
+
base_url=base_url,
|
55
|
+
config_path=config_path,
|
56
|
+
cache_path=cache_path,
|
57
|
+
logger=logger,
|
58
|
+
)
|
59
|
+
if result.error is not None:
|
60
|
+
await function_executor.destroy()
|
61
|
+
function_executor = None
|
62
|
+
|
63
|
+
return FunctionExecutorCreated(
|
64
|
+
function_executor=function_executor,
|
65
|
+
output=await _initialization_result_to_fe_creation_output(
|
66
|
+
function_executor_description=function_executor_description,
|
67
|
+
result=result,
|
68
|
+
blob_store=blob_store,
|
69
|
+
logger=logger,
|
70
|
+
),
|
71
|
+
)
|
72
|
+
except BaseException as e:
|
73
|
+
if isinstance(e, asyncio.CancelledError):
|
74
|
+
logger.info("function executor startup was cancelled")
|
75
|
+
return FunctionExecutorCreated(
|
76
|
+
function_executor=None,
|
77
|
+
output=FunctionExecutorStartupOutput(
|
78
|
+
function_executor_description=function_executor_description,
|
79
|
+
termination_reason=FunctionExecutorTerminationReason.FUNCTION_EXECUTOR_TERMINATION_REASON_REMOVED_FROM_DESIRED_STATE,
|
80
|
+
),
|
81
|
+
)
|
82
|
+
else:
|
83
|
+
logger.error(
|
84
|
+
"failed to create function executor due to platform error",
|
85
|
+
exc_info=e,
|
86
|
+
)
|
87
|
+
return FunctionExecutorCreated(
|
88
|
+
function_executor=None,
|
89
|
+
output=FunctionExecutorStartupOutput(
|
90
|
+
function_executor_description=function_executor_description,
|
91
|
+
termination_reason=FunctionExecutorTerminationReason.FUNCTION_EXECUTOR_TERMINATION_REASON_STARTUP_FAILED_INTERNAL_ERROR,
|
92
|
+
),
|
93
|
+
)
|
94
|
+
|
95
|
+
|
96
|
+
async def _initialization_result_to_fe_creation_output(
|
97
|
+
function_executor_description: FunctionExecutorDescription,
|
98
|
+
result: FunctionExecutorInitializationResult,
|
99
|
+
blob_store: BLOBStore,
|
100
|
+
logger: Any,
|
101
|
+
) -> FunctionExecutorStartupOutput:
|
102
|
+
"""Converts FunctionExecutorInitializationResult to FunctionExecutorCreationOutput.
|
103
|
+
|
104
|
+
Uploads stdout and stderr to blob store if they are present. Does only one attempt to do that.
|
105
|
+
Doesn't raise any exceptions."""
|
106
|
+
termination_reason: FunctionExecutorTerminationReason = None
|
107
|
+
if result.error is not None:
|
108
|
+
if result.error == FunctionExecutorInitializationError.FUNCTION_ERROR:
|
109
|
+
termination_reason = (
|
110
|
+
FunctionExecutorTerminationReason.FUNCTION_EXECUTOR_TERMINATION_REASON_STARTUP_FAILED_FUNCTION_ERROR
|
111
|
+
)
|
112
|
+
elif result.error == FunctionExecutorInitializationError.FUNCTION_TIMEOUT:
|
113
|
+
termination_reason = (
|
114
|
+
FunctionExecutorTerminationReason.FUNCTION_EXECUTOR_TERMINATION_REASON_STARTUP_FAILED_FUNCTION_TIMEOUT
|
115
|
+
)
|
116
|
+
else:
|
117
|
+
logger.error(
|
118
|
+
"unexpected function executor initialization error code",
|
119
|
+
error_code=FunctionExecutorInitializationError.name(result.error),
|
120
|
+
)
|
121
|
+
termination_reason = (
|
122
|
+
FunctionExecutorTerminationReason.FUNCTION_EXECUTOR_TERMINATION_REASON_STARTUP_FAILED_INTERNAL_ERROR
|
123
|
+
)
|
124
|
+
|
125
|
+
stdout: Optional[DataPayload] = None
|
126
|
+
if result.stdout is not None:
|
127
|
+
url = f"{function_executor_description.output_payload_uri_prefix}/{function_executor_description.id}/stdout"
|
128
|
+
stdout = await _upload_initialization_output(
|
129
|
+
output_name="stdout",
|
130
|
+
output=result.stdout,
|
131
|
+
output_url=url,
|
132
|
+
blob_store=blob_store,
|
133
|
+
logger=logger,
|
134
|
+
)
|
135
|
+
|
136
|
+
stderr: Optional[DataPayload] = None
|
137
|
+
if result.stderr is not None:
|
138
|
+
url = f"{function_executor_description.output_payload_uri_prefix}/{function_executor_description.id}/stderr"
|
139
|
+
stderr = await _upload_initialization_output(
|
140
|
+
output_name="stderr",
|
141
|
+
output=result.stderr,
|
142
|
+
output_url=url,
|
143
|
+
blob_store=blob_store,
|
144
|
+
logger=logger,
|
145
|
+
)
|
146
|
+
|
147
|
+
return FunctionExecutorStartupOutput(
|
148
|
+
function_executor_description=function_executor_description,
|
149
|
+
termination_reason=termination_reason,
|
150
|
+
stdout=stdout,
|
151
|
+
stderr=stderr,
|
152
|
+
)
|
153
|
+
|
154
|
+
|
155
|
+
async def _upload_initialization_output(
|
156
|
+
output_name: str, output: str, output_url: str, blob_store: BLOBStore, logger: Any
|
157
|
+
) -> Optional[DataPayload]:
|
158
|
+
"""Uploads text to blob store. Returns None if the upload fails.
|
159
|
+
|
160
|
+
Doesn't raise any exceptions.
|
161
|
+
"""
|
162
|
+
try:
|
163
|
+
output_bytes: bytes = output.encode()
|
164
|
+
await blob_store.put(output_url, output_bytes, logger)
|
165
|
+
logger.info(
|
166
|
+
f"function executor initialization output {output_name} uploaded to blob store",
|
167
|
+
size=len(output_bytes),
|
168
|
+
)
|
169
|
+
return DataPayload(
|
170
|
+
uri=output_url,
|
171
|
+
size=len(output_bytes),
|
172
|
+
sha256_hash=compute_hash(output_bytes),
|
173
|
+
encoding=DataPayloadEncoding.DATA_PAYLOAD_ENCODING_UTF8_TEXT,
|
174
|
+
encoding_version=0,
|
175
|
+
)
|
176
|
+
except Exception as e:
|
177
|
+
logger.error(
|
178
|
+
f"failed to upload function executor initialization output {output_name} to blob store",
|
179
|
+
exc_info=e,
|
180
|
+
)
|
181
|
+
return None
|
182
|
+
|
183
|
+
|
184
|
+
async def _create_function_executor(
|
185
|
+
function_executor_description: FunctionExecutorDescription,
|
186
|
+
function_executor_server_factory: FunctionExecutorServerFactory,
|
187
|
+
blob_store: BLOBStore,
|
188
|
+
executor_id: str,
|
189
|
+
base_url: str,
|
190
|
+
config_path: str,
|
191
|
+
cache_path: Path,
|
192
|
+
logger: Any,
|
193
|
+
) -> Tuple[FunctionExecutor, FunctionExecutorInitializationResult]:
|
194
|
+
"""Creates a function executor.
|
195
|
+
|
196
|
+
Raises Exception on platform error.
|
197
|
+
"""
|
198
|
+
graph: SerializedObject = await download_graph(
|
199
|
+
function_executor_description=function_executor_description,
|
200
|
+
cache_path=cache_path,
|
201
|
+
blob_store=blob_store,
|
202
|
+
logger=logger,
|
203
|
+
)
|
204
|
+
|
205
|
+
gpu_count: int = 0
|
206
|
+
if function_executor_description.resources.HasField("gpu"):
|
207
|
+
gpu_count = function_executor_description.resources.gpu.count
|
208
|
+
|
209
|
+
config: FunctionExecutorServerConfiguration = FunctionExecutorServerConfiguration(
|
210
|
+
executor_id=executor_id,
|
211
|
+
function_executor_id=function_executor_description.id,
|
212
|
+
namespace=function_executor_description.namespace,
|
213
|
+
graph_name=function_executor_description.graph_name,
|
214
|
+
graph_version=function_executor_description.graph_version,
|
215
|
+
function_name=function_executor_description.function_name,
|
216
|
+
image_uri=None,
|
217
|
+
secret_names=list(function_executor_description.secret_names),
|
218
|
+
cpu_ms_per_sec=function_executor_description.resources.cpu_ms_per_sec,
|
219
|
+
memory_bytes=function_executor_description.resources.memory_bytes,
|
220
|
+
disk_bytes=function_executor_description.resources.disk_bytes,
|
221
|
+
gpu_count=gpu_count,
|
222
|
+
)
|
223
|
+
if function_executor_description.HasField("image_uri"):
|
224
|
+
config.image_uri = function_executor_description.image_uri
|
225
|
+
|
226
|
+
initialize_request: InitializeRequest = InitializeRequest(
|
227
|
+
namespace=function_executor_description.namespace,
|
228
|
+
graph_name=function_executor_description.graph_name,
|
229
|
+
graph_version=function_executor_description.graph_version,
|
230
|
+
function_name=function_executor_description.function_name,
|
231
|
+
graph=graph,
|
232
|
+
)
|
233
|
+
customer_code_timeout_sec: Optional[float] = None
|
234
|
+
if function_executor_description.HasField("customer_code_timeout_ms"):
|
235
|
+
customer_code_timeout_sec = (
|
236
|
+
function_executor_description.customer_code_timeout_ms / 1000.0
|
237
|
+
)
|
238
|
+
|
239
|
+
function_executor: FunctionExecutor = FunctionExecutor(
|
240
|
+
server_factory=function_executor_server_factory, logger=logger
|
241
|
+
)
|
242
|
+
|
243
|
+
try:
|
244
|
+
result: FunctionExecutorInitializationResult = (
|
245
|
+
await function_executor.initialize(
|
246
|
+
config=config,
|
247
|
+
initialize_request=initialize_request,
|
248
|
+
base_url=base_url,
|
249
|
+
config_path=config_path,
|
250
|
+
customer_code_timeout_sec=customer_code_timeout_sec,
|
251
|
+
)
|
252
|
+
)
|
253
|
+
return (function_executor, result)
|
254
|
+
except BaseException: # includes asyncio.CancelledError and anything else
|
255
|
+
await function_executor.destroy()
|
256
|
+
raise
|
@@ -11,7 +11,7 @@ async def destroy_function_executor(
|
|
11
11
|
termination_reason: FunctionExecutorTerminationReason,
|
12
12
|
logger: Any,
|
13
13
|
) -> FunctionExecutorDestroyed:
|
14
|
-
"""Destroys a function executor.
|
14
|
+
"""Destroys a function executor if it's not None.
|
15
15
|
|
16
16
|
Doesn't raise any exceptions.
|
17
17
|
"""
|
{indexify-0.4.5 → indexify-0.4.7}/src/indexify/executor/function_executor_controller/events.py
RENAMED
@@ -2,11 +2,11 @@ from enum import Enum
|
|
2
2
|
from typing import Optional
|
3
3
|
|
4
4
|
from indexify.executor.function_executor.function_executor import (
|
5
|
-
FunctionError,
|
6
5
|
FunctionExecutor,
|
7
6
|
)
|
8
7
|
from indexify.proto.executor_api_pb2 import FunctionExecutorTerminationReason
|
9
8
|
|
9
|
+
from .function_executor_startup_output import FunctionExecutorStartupOutput
|
10
10
|
from .task_info import TaskInfo
|
11
11
|
|
12
12
|
|
@@ -37,21 +37,17 @@ class FunctionExecutorCreated(BaseEvent):
|
|
37
37
|
"""
|
38
38
|
Event indicating that Function Executor got created or failed.
|
39
39
|
|
40
|
-
|
41
|
-
The function_executor field is None if any errors happened.
|
40
|
+
The function_executor field is None if the function executor was not created.
|
42
41
|
"""
|
43
42
|
|
44
43
|
def __init__(
|
45
44
|
self,
|
45
|
+
output: FunctionExecutorStartupOutput,
|
46
46
|
function_executor: Optional[FunctionExecutor] = None,
|
47
|
-
function_error: Optional[FunctionError] = None,
|
48
|
-
termination_reason: FunctionExecutorTerminationReason = None, # type: Optional[FunctionExecutorTerminationReason]
|
49
47
|
):
|
50
48
|
super().__init__(EventType.FUNCTION_EXECUTOR_CREATED)
|
51
49
|
self.function_executor: Optional[FunctionExecutor] = function_executor
|
52
|
-
self.
|
53
|
-
# Reason for FE termination if failed to create FE (.function_executor is None).
|
54
|
-
self.termination_reason = termination_reason
|
50
|
+
self.output: FunctionExecutorStartupOutput = output
|
55
51
|
|
56
52
|
|
57
53
|
class FunctionExecutorDestroyed(BaseEvent):
|
@@ -107,8 +103,8 @@ class TaskPreparationFinished(BaseEvent):
|
|
107
103
|
def __str__(self) -> str:
|
108
104
|
return (
|
109
105
|
f"Event(type={self.event_type.name}, "
|
110
|
-
f"task_id={self.task_info.task.id}, "
|
111
|
-
f"allocation_id={self.task_info.allocation_id}), "
|
106
|
+
f"task_id={self.task_info.allocation.task.id}, "
|
107
|
+
f"allocation_id={self.task_info.allocation.allocation_id}), "
|
112
108
|
f"is_success={self.is_success}"
|
113
109
|
)
|
114
110
|
|
@@ -147,8 +143,8 @@ class TaskExecutionFinished(BaseEvent):
|
|
147
143
|
)
|
148
144
|
return (
|
149
145
|
f"Event(type={self.event_type.name}, "
|
150
|
-
f"task_id={self.task_info.task.id}, "
|
151
|
-
f"allocation_id={self.task_info.allocation_id}), "
|
146
|
+
f"task_id={self.task_info.allocation.task.id}, "
|
147
|
+
f"allocation_id={self.task_info.allocation.allocation_id}), "
|
152
148
|
f"function_executor_termination_reason={function_executor_termination_reason_str}"
|
153
149
|
)
|
154
150
|
|
@@ -166,7 +162,7 @@ class TaskOutputUploadFinished(BaseEvent):
|
|
166
162
|
def __str__(self) -> str:
|
167
163
|
return (
|
168
164
|
f"Event(type={self.event_type.name}, "
|
169
|
-
f"task_id={self.task_info.task.id}, "
|
170
|
-
f"allocation_id={self.task_info.allocation_id}), "
|
165
|
+
f"task_id={self.task_info.allocation.task.id}, "
|
166
|
+
f"allocation_id={self.task_info.allocation.allocation_id}), "
|
171
167
|
f"is_success={self.is_success}"
|
172
168
|
)
|