indexify 0.3.3__py3-none-any.whl → 0.3.5__py3-none-any.whl

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/cli/cli.py CHANGED
@@ -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=version("indexify"),
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
- executor_id: str,
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=executor_id,
61
+ executor_id=id,
60
62
  config_path=self._config_path,
61
63
  )
62
64
 
@@ -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
@@ -3,8 +3,7 @@ from typing import Any
3
3
 
4
4
  import grpc
5
5
 
6
- from indexify.function_executor.proto.configuration import GRPC_CHANNEL_OPTIONS
7
-
6
+ from .client_configuration import GRPC_CHANNEL_OPTIONS
8
7
  from .function_executor_server import FunctionExecutorServer
9
8
 
10
9
 
@@ -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
 
@@ -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
- self._state.function_executor.invocation_state_client().remove_task_to_invocation_id_entry(
148
- task_id=self._task_id
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=version("indexify"),
34
+ executor_version=executor_version,
34
35
  addr="",
35
36
  function_allowlist=function_allowlist,
36
37
  labels=probe_info.labels,
@@ -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, Union
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=_func_is_reducer(self._function_wrapper),
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 _func_is_reducer(func_wrapper: TensorlakeFunctionWrapper) -> bool:
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):
@@ -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
  }
@@ -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\x08_success2\xf2\x02\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.RunTaskResponseb\x06proto3'
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["_FUNCTIONEXECUTOR"]._serialized_start = 2378
64
- _globals["_FUNCTIONEXECUTOR"]._serialized_end = 2748
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)
@@ -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: ...
@@ -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
+ )
@@ -17,5 +17,3 @@ GRPC_SERVER_OPTIONS = [
17
17
  ("grpc.max_send_message_length", _MAX_GRPC_MESSAGE_LENGTH),
18
18
  ("grpc.so_reuseport", _REUSE_SERVER_PORT),
19
19
  ]
20
-
21
- GRPC_CHANNEL_OPTIONS = GRPC_SERVER_OPTIONS
@@ -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, Union
1
+ from typing import Iterator, Optional
2
2
 
3
3
  import grpc
4
4
  import structlog
5
- from tensorlake.functions_sdk.functions import TensorlakeCompute
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._function: Optional[Union[TensorlakeCompute, TensorlakeCompute]] = None
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
- self._function = graph_serializer.deserialize(graph[request.function_name])
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())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: indexify
3
- Version: 0.3.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.28.1,<0.29.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.7,<0.2.0)
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,44 +1,47 @@
1
- indexify/cli/cli.py,sha256=y6JNaMd5by7_v3jE1iah1krlvfzbN4r5A2WkgGTy1Ts,11427
1
+ indexify/cli/cli.py,sha256=WcQy4QrO2NM4Xfenzb11WzJbC8lOpMgE8GgHAkUNcZE,11504
2
2
  indexify/executor/README.md,sha256=ozC6_hMkhQQNVCMEpBxwiUALz6lwErPQxNxQfQDqnG4,2029
3
3
  indexify/executor/api_objects.py,sha256=k5tKYxaWml0sSECoEDzamCYeJnlD7zO2M7E_qGwyMrg,1032
4
4
  indexify/executor/downloader.py,sha256=Vrq1dAW4BifG62tlqFnImiMxdezIgOZcByTRnhDsnnw,6457
5
- indexify/executor/executor.py,sha256=lln0p0cVN2aNY3bsHFp7Phbaa2q9gnQABi1xEPxo1Nc,5859
6
- indexify/executor/function_executor/function_executor.py,sha256=a9pAWQWDLJL-i5bp1PEMD2eMYOTvXAh_1jQsXcL_JCQ,5226
5
+ indexify/executor/executor.py,sha256=hyAQKJ80IaPB-A_YRRld4yqYhAifLvMkQ8qYNMQimPI,5892
6
+ indexify/executor/function_executor/function_executor.py,sha256=837r91kL1Nt5Ct9LVFdpB89fhtHctV-c2PrgbyVSFlE,5833
7
7
  indexify/executor/function_executor/function_executor_state.py,sha256=_85dpaudYM0sekOqwjMxKGdK7MNQdTGUhHi67sqVHyY,2853
8
+ indexify/executor/function_executor/health_checker.py,sha256=UzAqqWO2y0DLhxm639mTDrEIYNY7gZ3T_zdgPSDuVJ4,2747
8
9
  indexify/executor/function_executor/invocation_state_client.py,sha256=jxElxnYFfdwCxKfKvQsjLIE-Z_1386wxednJ2pGKSL0,8581
10
+ indexify/executor/function_executor/server/client_configuration.py,sha256=gOywMus0cotlX6NKIadEJwvOmBE-LbGE_wvoMi5-HzY,994
9
11
  indexify/executor/function_executor/server/function_executor_server.py,sha256=_DLivLDikupZusRk8gVWDk7fWPT9XjZ4un1yWSlOObs,883
10
12
  indexify/executor/function_executor/server/function_executor_server_factory.py,sha256=pGbJMQfC5TNvyWOs6VDKdqd2PK5OHQh5_wSDP-E7DbI,1677
11
- indexify/executor/function_executor/server/subprocess_function_executor_server.py,sha256=DxQMwAvQi03OGo2sFruUrxwcMPG8In4C62L3sped2FI,694
12
- indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py,sha256=cVr2wXQL5zVlq-Ep44ZBXBFCQbrbZSMscjRmzVDakvk,4295
13
- indexify/executor/function_executor/single_task_runner.py,sha256=NGji5iIoA9vxRzSvyUTL3Gs5g4HMq5b1LYN5ZsENcls,6244
13
+ indexify/executor/function_executor/server/subprocess_function_executor_server.py,sha256=JekDOqF7oFD4J6zcN3xB0Dxd1cgpEXMOsb_rKZOeBlI,668
14
+ indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py,sha256=FYExuYZZ7CUcznUobtnxvd2hVjUjpB9Dkav0FFcA0hM,4118
15
+ indexify/executor/function_executor/single_task_runner.py,sha256=CwLN2pLJpORDjxgxME5-xQCBJ_mzmrdnrzjB7n4sqZo,7794
14
16
  indexify/executor/function_executor/task_input.py,sha256=8pBRuaQbBBPrDWwByOKZlOaXu6UDmJUO5w-6XxAYSgY,582
15
17
  indexify/executor/function_executor/task_output.py,sha256=3-qcT1aigmOFEp6QSJtUcQfqeJfrxvo265qgk9WAUVg,1064
16
18
  indexify/executor/runtime_probes.py,sha256=bo6Dq6AGZpJH099j0DHtVSDEH80tv3j9MXf3VXSx_p8,2182
17
- indexify/executor/task_fetcher.py,sha256=Cpm-LRZz1MSfW-xHJbIaKc1wxzRhIrud9GTOIxWODt0,2883
19
+ indexify/executor/task_fetcher.py,sha256=59Cn79bXpbPFEj2bZCVFRaLaNKPAeRyJeiEsZE3F7Ys,2911
18
20
  indexify/executor/task_reporter.py,sha256=eueJNHYJIwAm8lY8SQJrUOWC-Nk-DPesDis1YTR4k7c,6643
19
21
  indexify/executor/task_runner.py,sha256=RSFeJYhQ_agXXPBm8u13HErSUPZGsCGwV1stgS7g258,5035
20
22
  indexify/function_executor/README.md,sha256=TAcbYYe6noUMriaQabJAaZ8a2SAYzlXl7hIdTfULqYY,950
21
23
  indexify/function_executor/handlers/run_function/function_inputs_loader.py,sha256=StSJCp-kkOWUuUIzONnoqtcB37nzBYGcIVy2oTEwOIQ,1588
22
- indexify/function_executor/handlers/run_function/handler.py,sha256=DY_aIR8MZsa1cnFxbVEHhcxQSqBwW4cYRN9NhzuDDFo,5090
24
+ indexify/function_executor/handlers/run_function/handler.py,sha256=-GPM9G9GkkJtmB776RPKReFnus5hMoAw6IC0rV2WE5s,5209
23
25
  indexify/function_executor/handlers/run_function/request_validator.py,sha256=GS7_zxAlyNg0vpUrhot-DpVWFyI9Y9P8jvb7UuO4b1A,856
24
26
  indexify/function_executor/handlers/run_function/response_helper.py,sha256=FJVl-LyoRBx9HRaOo_umveiWzuh4anO7aXUmEMEki20,3074
27
+ indexify/function_executor/info.py,sha256=kR_i84pLqAQI5AKLYuXg3mEaVIMmHZK-Hx8Dmv-_slA,454
25
28
  indexify/function_executor/initialize_request_validator.py,sha256=agYWGRHUC-7IuYtm9NPjcVo5SVOWM4PxewA93dqdkJM,682
26
29
  indexify/function_executor/invocation_state/invocation_state_proxy_server.py,sha256=YEnxvWV8NFVK_CxHI_C-BNizuagalY3ieN62IOxNttU,7023
27
30
  indexify/function_executor/invocation_state/proxied_invocation_state.py,sha256=rjZ2192bSXonNKkaDaByeOL-wVx6x6Qrtio0UVzGSz8,944
28
31
  indexify/function_executor/invocation_state/response_validator.py,sha256=05Y9_5s010owaDb6OUia9W9Alx1r1zJ179HboEkT-Xk,896
29
- indexify/function_executor/main.py,sha256=uOzVUhl4LzGJ9Cw3kyyFddaEIMxRETEKFHPnvJVtc50,1152
30
- indexify/function_executor/proto/configuration.py,sha256=oHp_Hh1_XdL4v7M2Ok-Z9r7ClTxiWdSP1Ip-NK4Ee6E,1096
31
- indexify/function_executor/proto/function_executor.proto,sha256=Ae6vMCNnacHWmrF6aZVPzIVVzG5sJgP7LXV4vIUBKZM,3978
32
- indexify/function_executor/proto/function_executor_pb2.py,sha256=X2G2xZQy8VRWqlDKV2dUgD3CkEecFx6Jp2EuTuXrx9o,7358
33
- indexify/function_executor/proto/function_executor_pb2.pyi,sha256=TQEOl3W1s4fxtp1g8Hi5S-keMF25DY5-6miyDVHhBkE,7168
34
- indexify/function_executor/proto/function_executor_pb2_grpc.py,sha256=xrqIDrcl1PTyQTGAAGrgSDKEtZilC445Op0tJ7LmS5Q,8716
32
+ indexify/function_executor/main.py,sha256=LvcEAPPi-yy2eyatNssihcJRXjAzz5GCcMftvLF9ciU,1224
33
+ indexify/function_executor/proto/function_executor.proto,sha256=GZ2cAkwrNQTC6GRFTckmyGo3P-ywgY8ZKsVuuQL-x8c,4915
34
+ indexify/function_executor/proto/function_executor_pb2.py,sha256=MtvY7kAxf-O6zu6XUkV3-IBew3Np19ceuPtmk-sxWsQ,8559
35
+ indexify/function_executor/proto/function_executor_pb2.pyi,sha256=QYZ3MH7Z72-xCsrzyMEeUVCcxRg2mjOIosV2bLlwSAI,8179
36
+ indexify/function_executor/proto/function_executor_pb2_grpc.py,sha256=OGSzzbZKtOSNGemTJLX0L96_jkxUiZSYJQM56LHzZ-o,12734
35
37
  indexify/function_executor/proto/message_validator.py,sha256=OKXPYgy5L9c-spnV9Zjv7PA_yxwzvykfhbYylYx8cwQ,1456
36
- indexify/function_executor/server.py,sha256=tJzUy_v4BT8Le9G3hgtiuDJo9YVFkAU2dVISSsX36II,1061
37
- indexify/function_executor/service.py,sha256=i3bI7RSKSr3cDiNFoZdl4TSY_SMKlXBXPdExjvaAoBY,5606
38
+ indexify/function_executor/proto/server_configuration.py,sha256=FzrusxLU62IfvbZ42IjwmPROsDQMi5mCOu41hRA4E7s,1052
39
+ indexify/function_executor/server.py,sha256=gOAl_-cT8Z4yC_bjD4adaHY4EzsjRm9RuykeCNGp8Mc,1068
40
+ indexify/function_executor/service.py,sha256=OUqlh0lirRbHNsgpDOEwbaGpDptAs1-GoeKveYCq7zk,6506
38
41
  indexify/utils/README.md,sha256=2g8-H9GopacOW4YrViZc0QsaJPtK-Fox7GyfX01kcDk,86
39
42
  indexify/utils/http_client.py,sha256=deMlmAu4E_ZXV3blCdWNag3uO_cyD-GsMZjFFmO5r7s,3541
40
43
  indexify/utils/logging.py,sha256=c6NwzY7uVHMRJc8f2w2KF36rNkeZVoQfGdq7suIg9s8,2025
41
- indexify-0.3.3.dist-info/METADATA,sha256=VLMu3g8ZamLGLCjjqwPrBxqg8ZStvSZooP9ITl-BbHw,1383
42
- indexify-0.3.3.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
43
- indexify-0.3.3.dist-info/entry_points.txt,sha256=pJG0YRnypesbiNJHuObfHEkjk0p_ZvEDTyyTH0kGVTY,108
44
- indexify-0.3.3.dist-info/RECORD,,
44
+ indexify-0.3.5.dist-info/METADATA,sha256=bn5MHa523My7wk17i-8_ev8hnFrhABt1Q4GLXcsoKpk,1373
45
+ indexify-0.3.5.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
46
+ indexify-0.3.5.dist-info/entry_points.txt,sha256=pJG0YRnypesbiNJHuObfHEkjk0p_ZvEDTyyTH0kGVTY,108
47
+ indexify-0.3.5.dist-info/RECORD,,