indexify 0.4.26__py3-none-any.whl → 0.4.27__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.
@@ -308,10 +308,7 @@ async def _initialize_server(
308
308
  customer_code_timeout_sec: float,
309
309
  logger: Any,
310
310
  ) -> FunctionExecutorInitializationResult:
311
- with (
312
- metric_initialize_rpc_errors.count_exceptions(),
313
- metric_initialize_rpc_latency.time(),
314
- ):
311
+ with metric_initialize_rpc_latency.time():
315
312
  try:
316
313
  initialize_response: InitializeResponse = await stub.initialize(
317
314
  initialize_request,
@@ -322,6 +319,9 @@ async def _initialize_server(
322
319
  response=initialize_response,
323
320
  )
324
321
  except grpc.aio.AioRpcError as e:
322
+ # Increment the metric manually as we're not raising this exception.
323
+ metric_initialize_rpc_errors.inc()
324
+ metric_create_errors.inc()
325
325
  if e.code() == grpc.StatusCode.DEADLINE_EXCEEDED:
326
326
  return FunctionExecutorInitializationResult(
327
327
  is_timeout=True,
@@ -0,0 +1,26 @@
1
+ import asyncio
2
+ from typing import Any, Optional
3
+
4
+
5
+ async def shielded_await(task: asyncio.Task, logger: Any) -> Any:
6
+ """Awaits the supplied task and ignores cancellations until it's done.
7
+
8
+ Cancels itself if the task is cancelled once the task is done.
9
+ """
10
+ cancelled_error: Optional[asyncio.CancelledError] = None
11
+
12
+ while not task.done():
13
+ try:
14
+ # Shield to make sure that task is not cancelled.
15
+ await asyncio.shield(task)
16
+ except asyncio.CancelledError as e:
17
+ logger.info(
18
+ "ignoring aio task cancellation until it's finished",
19
+ task_name=task.get_name(),
20
+ )
21
+ cancelled_error = e
22
+
23
+ if cancelled_error is not None:
24
+ raise cancelled_error
25
+ else:
26
+ return task.result()
@@ -25,6 +25,7 @@ from indexify.proto.executor_api_pb2 import (
25
25
  FunctionExecutorTerminationReason,
26
26
  )
27
27
 
28
+ from .aio_utils import shielded_await
28
29
  from .downloads import download_graph
29
30
  from .events import FunctionExecutorCreated
30
31
 
@@ -82,8 +83,13 @@ async def create_function_executor(
82
83
  logger=logger,
83
84
  )
84
85
  if fe_created_event.function_executor is None:
86
+ # _to_fe_created_event doesn't like the FE, destroy it.
87
+ fe_destroy_task: asyncio.Task = asyncio.create_task(
88
+ function_executor.destroy(),
89
+ name=f"destroy function executor {function_executor_description.id}",
90
+ )
85
91
  try:
86
- await asyncio.shield(function_executor.destroy())
92
+ await shielded_await(fe_destroy_task, logger)
87
93
  except asyncio.CancelledError:
88
94
  # destroy() finished due to the shield, return fe_created_event.
89
95
  pass
@@ -230,9 +236,16 @@ async def _create_function_executor(
230
236
  )
231
237
  )
232
238
  return (function_executor, result)
233
- except BaseException: # includes asyncio.CancelledError and anything else
239
+ except BaseException:
240
+ fe_destroy_task: asyncio.Task = asyncio.create_task(
241
+ function_executor.destroy(),
242
+ name=f"destroy function executor {function_executor_description.id}",
243
+ )
234
244
  # This await is a cancellation point, need to shield to ensure we destroyed the FE.
235
- await asyncio.shield(function_executor.destroy())
245
+ await shielded_await(
246
+ fe_destroy_task,
247
+ logger,
248
+ )
236
249
  raise
237
250
 
238
251
 
@@ -407,7 +407,7 @@ class FunctionExecutorController:
407
407
  """Spawns an aio task for the supplied coroutine.
408
408
 
409
409
  The coroutine should return an event that will be added to the FE controller events.
410
- The coroutine should not raise any exceptions including BaseException and asyncio.CancelledError.
410
+ The coroutine should not raise any exceptions including BaseException.
411
411
  on_exception event will be added to the FE controller events if the aio task raises an unexpected exception.
412
412
  on_exception is required to not silently stall the task processing due to an unexpected exception.
413
413
  If task_info is not None, the aio task will be associated with the task_info while the aio task is running.
@@ -422,6 +422,14 @@ class FunctionExecutorController:
422
422
  async def coroutine_wrapper() -> None:
423
423
  try:
424
424
  self._add_event(await aio, source=aio_task_name)
425
+ except asyncio.CancelledError:
426
+ # Workaround for scenario when coroutine_wrapper gets cancelled at `await aio` before aio starts.
427
+ # In this case aio doesn't handle the cancellation and doesn't return the right event.
428
+ # A fix for this is to cancel aio instead of coroutine_wrapper. We'll need to keep
429
+ # references to both coroutine_wrapper and aio, cause event loop uses weak references to
430
+ # tasks. Not doing this for now. Using on_exception is good enough because not started aios don't
431
+ # need to do anything special on cancellation.
432
+ self._add_event(on_exception, source=aio_task_name)
425
433
  except BaseException as e:
426
434
  logger.error(
427
435
  "unexpected exception in aio task",
@@ -4,6 +4,7 @@ from typing import Any, List, Optional
4
4
  from indexify.executor.function_executor.function_executor import FunctionExecutor
5
5
  from indexify.proto.executor_api_pb2 import FunctionExecutorTerminationReason
6
6
 
7
+ from .aio_utils import shielded_await
7
8
  from .events import FunctionExecutorTerminated
8
9
 
9
10
 
@@ -18,7 +19,7 @@ async def terminate_function_executor(
18
19
 
19
20
  The supplied lock is used to ensure that if a destroy operation is in progress,
20
21
  then another caller won't return immediately assuming that the destroy is complete
21
- due to its idempotency.
22
+ due to its idempotency. Ignores cancellations while destroying the function executor.
22
23
 
23
24
  Doesn't raise any exceptions.
24
25
  """
@@ -29,9 +30,12 @@ async def terminate_function_executor(
29
30
  logger.info(
30
31
  "destroying function executor",
31
32
  )
33
+ fe_destroy_task: asyncio.Task = asyncio.create_task(
34
+ function_executor.destroy(),
35
+ name="destroy function executor",
36
+ )
32
37
  try:
33
- # This await is a cancellation point, need to shield to ensure we destroyed the FE.
34
- await asyncio.shield(function_executor.destroy())
38
+ await shielded_await(fe_destroy_task, logger)
35
39
  except asyncio.CancelledError:
36
40
  # We actually destroyed the FE so we can return without error.
37
41
  pass
@@ -193,6 +193,8 @@ class ExecutorStateReconciler:
193
193
  timeout=_DESIRED_EXECUTOR_STATES_TIMEOUT_SEC,
194
194
  )
195
195
  except asyncio.TimeoutError:
196
+ # These log lines really help to debug networking issues. When there are
197
+ # no networking issues and the fleet is not idle we don't get excessive logging here.
196
198
  self._logger.info(
197
199
  f"No desired state received from Server within {_DESIRED_EXECUTOR_STATES_TIMEOUT_SEC} sec, recreating the stream to ensure it is healthy"
198
200
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: indexify
3
- Version: 0.4.26
3
+ Version: 0.4.27
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
@@ -10,7 +10,7 @@ indexify/executor/blob_store/s3_blob_store.py,sha256=wJlDBTTaq48Vp1I0LvP2958b1Xe
10
10
  indexify/executor/channel_manager.py,sha256=ihKfWJmUqQvh4UKXewZLzyJWW_f50P4fnwPqPonrozw,6651
11
11
  indexify/executor/executor.py,sha256=rM7BmJDqC_YwdwPfDGFGiFO2WxOW3Nj8Z7rwRw8UcFk,6353
12
12
  indexify/executor/function_allowlist.py,sha256=PCelCW6qIe_2sH11BCKr7LDqarRV5kwNsrfB2EV7Zwo,1772
13
- indexify/executor/function_executor/function_executor.py,sha256=MrbGEqsxpzLVOrEAH_Kmm3cW3q_5h-GYUIkenuPvyT4,12288
13
+ indexify/executor/function_executor/function_executor.py,sha256=dTZ8y15ifu7GKmNLU-SQH5M3COa1_8ec_2439h67Pd8,12381
14
14
  indexify/executor/function_executor/health_checker.py,sha256=IxE0jnC99K_lvnizFLjXqS1942H8-FNAN4AlhLIjg2Y,6373
15
15
  indexify/executor/function_executor/invocation_state_client.py,sha256=q3YWnoTCYCtBrCOBlLd3b13_vwzibFOJJBHHami28Yc,11269
16
16
  indexify/executor/function_executor/metrics/function_executor.py,sha256=TDksxLRJr-P9ZKhF2Orsaxzzb4lVIBxFEjd_9Zv53Ng,6313
@@ -22,13 +22,14 @@ indexify/executor/function_executor/server/function_executor_server_factory.py,s
22
22
  indexify/executor/function_executor/server/subprocess_function_executor_server.py,sha256=JekDOqF7oFD4J6zcN3xB0Dxd1cgpEXMOsb_rKZOeBlI,668
23
23
  indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py,sha256=w5aGQPHWLpixlP9-BbZu6oL_muMA95-hr7WKVxiEL7Q,4303
24
24
  indexify/executor/function_executor_controller/__init__.py,sha256=VPuuBEYOKf7OWyPPjy-jGOv-d5xJqHvkJfFT_oj-AsE,492
25
+ indexify/executor/function_executor_controller/aio_utils.py,sha256=nohPk9k38FpZ87y5jgbb-UhUNvf-GRETkyyRBp7WnVw,804
25
26
  indexify/executor/function_executor_controller/completed_task_metrics.py,sha256=MhnC-ddgmTK4yTsuZxgTKnqZ-YSVeWn2EhbbiggsSKk,3664
26
- indexify/executor/function_executor_controller/create_function_executor.py,sha256=wCMlECcXZ9FMF0NlXqww6lbHRwy71w204q_Rh6nFoOE,10694
27
+ indexify/executor/function_executor_controller/create_function_executor.py,sha256=_VLmT9zmo0Hvt4K4WkC8PCB9qNgTv8k9QkwTSAOQRDU,11158
27
28
  indexify/executor/function_executor_controller/debug_event_loop.py,sha256=VJOKe_c9HjIDVCjhMY3Yqyeq1tAM1eVa2chZa6CMf-U,1016
28
29
  indexify/executor/function_executor_controller/downloads.py,sha256=B2dbaa6osp1_vCQ6WY_9znAca3Z2qqVzQAF2av3v8Pg,5304
29
30
  indexify/executor/function_executor_controller/events.py,sha256=M3taTBSxHG5CYWXfvk-BPtcV9bX-VDmSQDaNdGKK7Hk,5633
30
31
  indexify/executor/function_executor_controller/finalize_task.py,sha256=letfBqGXPTubvOfbRg7cvdgtvrwkSnSezx4XRknYvKM,6624
31
- indexify/executor/function_executor_controller/function_executor_controller.py,sha256=uBlQgSGIuVlxAQnT7Qs-T-8c5vABeITFCu_oY9-vNmU,39132
32
+ indexify/executor/function_executor_controller/function_executor_controller.py,sha256=WeetrN34i6YPA3z1VQvd_zw0bpodwiSArCb7-rYlm7M,39814
32
33
  indexify/executor/function_executor_controller/loggers.py,sha256=zEY2nt15gboX3SX6Kh1xjeCljZJZSE4lp27qNrg8yPY,3637
33
34
  indexify/executor/function_executor_controller/message_validators.py,sha256=7Hgu6GItKU5_zz_YHtHT5NlWIHnvof2P-o_21pto9vU,3128
34
35
  indexify/executor/function_executor_controller/metrics/completed_task_metrics.py,sha256=53EGBCLwCEV-RBBeyLPTElrtcveaEM0Fwxs9NmC1Hn8,2724
@@ -42,7 +43,7 @@ indexify/executor/function_executor_controller/run_task.py,sha256=kbQGhopCzbARcz
42
43
  indexify/executor/function_executor_controller/task_info.py,sha256=ufhb4PvQuXyY4JUlddNyN2bJQdUeGlMTMIRlKz_WzXc,1015
43
44
  indexify/executor/function_executor_controller/task_input.py,sha256=PHCzqpjzTzw4TJTn6wncon3P08EiTVRJazEYRbTqDu8,876
44
45
  indexify/executor/function_executor_controller/task_output.py,sha256=_uf0Wi1K-kaKPXED1RmKQZ9rpmjXFA4ONLn6ZOj2-UE,7127
45
- indexify/executor/function_executor_controller/terminate_function_executor.py,sha256=2eqcpAo5brfMPFtYCpTlI3FJ6ESRU9xUzbXDFU0lcP4,1561
46
+ indexify/executor/function_executor_controller/terminate_function_executor.py,sha256=GHkMEidd4zbkulFWAeLGX1HsXtZvPJXh4dEusgy2ioA,1731
46
47
  indexify/executor/host_resources/host_resources.py,sha256=eUyP05EX7QdOtQ5vbX_KCpvnBS2B7fl06UWeF9Oigns,3813
47
48
  indexify/executor/host_resources/nvidia_gpu.py,sha256=uTCkLXnozZSpax8VApt0QMMM9YcBUK9eggYpwmLz09I,3308
48
49
  indexify/executor/host_resources/nvidia_gpu_allocator.py,sha256=AOcXKglLyRD-GrZzyCoi_oDRJoaOhFKWBSlUOxHeAP8,2114
@@ -60,13 +61,13 @@ indexify/executor/monitoring/metrics.py,sha256=5BpNqDBDQiL2K962WDPQU2eSo5zD6I9vF
60
61
  indexify/executor/monitoring/prometheus_metrics_handler.py,sha256=KiGqSf7rkXTfbDwThyXFpFe2jnuZD5q-5SBP_0GDo8Y,591
61
62
  indexify/executor/monitoring/server.py,sha256=yzdYhcxnmY6uTQUMt3vatF5jilN52ZtfFseOmHyQpTo,1254
62
63
  indexify/executor/monitoring/startup_probe_handler.py,sha256=zXXsBU15SMlBx1bSFpxWDfed1VHtKKnwvLQ8-frpG98,425
63
- indexify/executor/state_reconciler.py,sha256=hPTjCUkXQV0HIwa5JczYpb5gvTGonQpkxqOvQXf-QU4,20057
64
+ indexify/executor/state_reconciler.py,sha256=8l4O0IjovnQNI39AQsst4qPb2qFdEncZiEvVl8nLjYI,20248
64
65
  indexify/executor/state_reporter.py,sha256=zf5UBhBZVv9SQ1Ju_bY8w6D_t1hBZ5YVXhjeFMEgRms,15208
65
66
  indexify/proto/executor_api.proto,sha256=yYLx3LTx2hGDFJX8myCosS3_eAWUMWdsWt59PH7O-QQ,12864
66
67
  indexify/proto/executor_api_pb2.py,sha256=ZrJg5ivsv-Kn8QRRsFWupdKCo6Eru6UNR8iYRqo5AhE,16458
67
68
  indexify/proto/executor_api_pb2.pyi,sha256=YfKsaIYaePZkpLTk_toAsWfH50xOOYfjjU3aWsci9w0,23151
68
69
  indexify/proto/executor_api_pb2_grpc.py,sha256=u9GEQV4nm_GvApRxjVo806CkgBMBVReb5IVrcaDaliY,7520
69
- indexify-0.4.26.dist-info/METADATA,sha256=ICKghkdJs_FKfudkQCaej0E3aQtwFy6gxauxyuIMXoE,1389
70
- indexify-0.4.26.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
71
- indexify-0.4.26.dist-info/entry_points.txt,sha256=rMJqbE5KPZIXTPIfAtVIM4zpUElqYVgEYd6i7N23zzg,49
72
- indexify-0.4.26.dist-info/RECORD,,
70
+ indexify-0.4.27.dist-info/METADATA,sha256=oBpQeVTH9cqACfgnpRxemwOHt5Y70tqbw-5bPNVB_NQ,1389
71
+ indexify-0.4.27.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
72
+ indexify-0.4.27.dist-info/entry_points.txt,sha256=rMJqbE5KPZIXTPIfAtVIM4zpUElqYVgEYd6i7N23zzg,49
73
+ indexify-0.4.27.dist-info/RECORD,,