indexify 0.3.7__py3-none-any.whl → 0.3.9__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
@@ -34,8 +34,6 @@ from indexify.executor.function_executor.server.subprocess_function_executor_ser
34
34
  SubprocessFunctionExecutorServerFactory,
35
35
  )
36
36
 
37
- logger = structlog.get_logger(module=__name__)
38
-
39
37
  custom_theme = Theme(
40
38
  {
41
39
  "info": "cyan",
@@ -160,25 +158,6 @@ def build_image(
160
158
  _create_image(obj, python_sdk_path)
161
159
 
162
160
 
163
- @app.command(help="Build default image for indexify")
164
- def build_default_image(
165
- python_version: Optional[str] = typer.Option(
166
- f"{sys.version_info.major}.{sys.version_info.minor}",
167
- help="Python version to use in the base image",
168
- )
169
- ):
170
- image = GetDefaultPythonImage(python_version)
171
-
172
- _build_image(image=image)
173
-
174
- console.print(
175
- Text(f"Built default indexify image with hash {image.hash()}\n", style="cyan"),
176
- Text(
177
- f"Don't forget to update your executors to run this image!", style="yellow"
178
- ),
179
- )
180
-
181
-
182
161
  @app.command(
183
162
  help="Runs Executor that connects to the Indexify server and starts running its tasks"
184
163
  )
@@ -208,6 +187,13 @@ def executor(
208
187
  ports: Tuple[int, int] = typer.Option(
209
188
  (50000, 51000), help="Range of localhost TCP ports to be used by the executor"
210
189
  ),
190
+ disable_automatic_function_executor_management: Annotated[
191
+ bool,
192
+ typer.Option(
193
+ "--disable-automatic-function-executor-management",
194
+ help="Disable automatic Function Executor management by Executor",
195
+ ),
196
+ ] = False,
211
197
  ):
212
198
  if dev:
213
199
  configure_development_mode_logging()
@@ -218,18 +204,20 @@ def executor(
218
204
  "At least one function must be specified when not running in development mode"
219
205
  )
220
206
 
221
- id = nanoid.generate()
222
207
  executor_version = version("indexify")
208
+ id = nanoid.generate()
209
+ logger = structlog.get_logger(module=__name__, executor_id=id)
210
+
223
211
  logger.info(
224
212
  "starting executor",
225
213
  server_addr=server_addr,
226
214
  config_path=config_path,
227
- executor_id=id,
228
215
  executor_version=executor_version,
229
216
  executor_cache=executor_cache,
230
217
  ports=ports,
231
218
  functions=function_uris,
232
219
  dev_mode=dev,
220
+ disable_automatic_function_executor_management=disable_automatic_function_executor_management,
233
221
  )
234
222
 
235
223
  executor_cache = Path(executor_cache).expanduser().absolute()
@@ -258,6 +246,7 @@ def executor(
258
246
  development_mode=dev,
259
247
  server_ports=range(ports[0], ports[1]),
260
248
  ),
249
+ disable_automatic_function_executor_management=disable_automatic_function_executor_management,
261
250
  ).run()
262
251
 
263
252
 
@@ -299,57 +288,7 @@ def _create_image(image: Image, python_sdk_path):
299
288
 
300
289
 
301
290
  def _build_image(image: Image, python_sdk_path: Optional[str] = None):
302
- docker_file = _generate_dockerfile(image, python_sdk_path=python_sdk_path)
303
- image_name = f"{image._image_name}:{image._tag}"
304
-
305
- # low_level_client = docker.APIClient(base_url=docker_client.api.base_url)
306
- docker_host = os.getenv("DOCKER_HOST", "unix:///var/run/docker.sock")
307
- low_level_client = docker.APIClient(base_url=docker_host)
308
- docker.api.build.process_dockerfile = lambda dockerfile, path: (
309
- "Dockerfile",
310
- dockerfile,
311
- )
312
- generator = low_level_client.build(
313
- dockerfile=docker_file,
314
- rm=True,
315
- path=".",
316
- tag=image_name,
317
- )
318
-
291
+ built_image, generator = image.build(python_sdk_path=python_sdk_path)
319
292
  for output in generator:
320
- for line in output.decode().splitlines():
321
- json_line = json.loads(line)
322
- if "stream" in json_line:
323
- print(json_line["stream"], end="")
324
-
325
- elif "errorDetail" in json_line:
326
- print(json_line["errorDetail"]["message"])
327
-
328
-
329
- def _generate_dockerfile(image, python_sdk_path: Optional[str] = None):
330
- docker_contents = [
331
- f"FROM {image._base_image}",
332
- "RUN mkdir -p ~/.indexify",
333
- f"RUN echo {image._image_name} > ~/.indexify/image_name", # TODO: Do we still use this in executors?
334
- f"RUN echo {image.hash()} > ~/.indexify/image_hash", # TODO: Do we still use this in executors?
335
- "WORKDIR /app",
336
- ]
337
-
338
- for build_op in image._build_ops:
339
- docker_contents.append(build_op.render())
340
-
341
- if python_sdk_path is not None:
342
- print(f"Building image {image._image_name} with local version of the SDK")
343
-
344
- if not os.path.exists(python_sdk_path):
345
- print(f"error: {python_sdk_path} does not exist")
346
- os.exit(1)
347
- docker_contents.append(f"COPY {python_sdk_path} /app/python-sdk")
348
- docker_contents.append("RUN (cd /app/python-sdk && pip install .)")
349
- else:
350
- docker_contents.append(
351
- f"RUN pip install indexify=={importlib.metadata.version('indexify')}"
352
- )
353
-
354
- docker_file = "\n".join(docker_contents)
355
- return docker_file
293
+ print(output)
294
+ print(f"built image: {built_image.tags[0]}")
@@ -27,6 +27,7 @@ class Executor:
27
27
  function_executor_server_factory: FunctionExecutorServerFactory,
28
28
  server_addr: str = "localhost:8900",
29
29
  config_path: Optional[str] = None,
30
+ disable_automatic_function_executor_management: bool = False,
30
31
  ):
31
32
  self._logger = structlog.get_logger(module=__name__)
32
33
  self._is_shutdown: bool = False
@@ -40,9 +41,11 @@ class Executor:
40
41
  self._base_url = f"{protocol}://{self._server_addr}"
41
42
  self._code_path = code_path
42
43
  self._task_runner = TaskRunner(
44
+ executor_id=id,
43
45
  function_executor_server_factory=function_executor_server_factory,
44
46
  base_url=self._base_url,
45
47
  config_path=config_path,
48
+ disable_automatic_function_executor_management=disable_automatic_function_executor_management,
46
49
  )
47
50
  self._downloader = Downloader(
48
51
  code_path=code_path, base_url=self._base_url, config_path=config_path
@@ -14,7 +14,8 @@ class FunctionExecutorServerConfiguration:
14
14
  configuration parameters or raise an exception if it can't implement
15
15
  them."""
16
16
 
17
- def __init__(self, image_uri: Optional[str]):
17
+ def __init__(self, executor_id: str, image_uri: Optional[str]):
18
+ self.executor_id: str = executor_id
18
19
  # Container image URI of the Function Executor Server.
19
20
  self.image_uri: Optional[str] = image_uri
20
21
 
@@ -28,6 +28,8 @@ class SubprocessFunctionExecutorServerFactory(FunctionExecutorServerFactory):
28
28
  try:
29
29
  port = self._allocate_port()
30
30
  args = [
31
+ "--executor-id",
32
+ config.executor_id,
31
33
  "--address",
32
34
  _server_address(port),
33
35
  ]
@@ -25,6 +25,7 @@ from .task_output import TaskOutput
25
25
  class SingleTaskRunner:
26
26
  def __init__(
27
27
  self,
28
+ executor_id: str,
28
29
  function_executor_state: FunctionExecutorState,
29
30
  task_input: TaskInput,
30
31
  function_executor_server_factory: FunctionExecutorServerFactory,
@@ -32,6 +33,7 @@ class SingleTaskRunner:
32
33
  config_path: Optional[str],
33
34
  logger: Any,
34
35
  ):
36
+ self._executor_id: str = executor_id
35
37
  self._state: FunctionExecutorState = function_executor_state
36
38
  self._task_input: TaskInput = task_input
37
39
  self._factory: FunctionExecutorServerFactory = function_executor_server_factory
@@ -76,6 +78,7 @@ class SingleTaskRunner:
76
78
  )
77
79
  config: FunctionExecutorServerConfiguration = (
78
80
  FunctionExecutorServerConfiguration(
81
+ executor_id=self._executor_id,
79
82
  image_uri=self._task_input.task.image_uri,
80
83
  )
81
84
  )
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import time
2
3
  from typing import Any, List, Optional, Tuple
3
4
 
4
5
  import nanoid
@@ -74,10 +75,18 @@ class TaskReporter:
74
75
  ),
75
76
  "files": output_files if len(output_files) > 0 else FORCE_MULTIPART,
76
77
  }
78
+
79
+ start_time = time.time()
77
80
  # Run in a separate thread to not block the main event loop.
78
81
  response = await asyncio.to_thread(
79
82
  self._client.post, url=f"{self._base_url}/internal/ingest_files", **kwargs
80
83
  )
84
+ end_time = time.time()
85
+ logger.info(
86
+ "task_outcome_reported",
87
+ response_time=end_time - start_time,
88
+ response_code=response.status_code,
89
+ )
81
90
 
82
91
  try:
83
92
  response.raise_for_status()
@@ -18,13 +18,19 @@ class TaskRunner:
18
18
 
19
19
  def __init__(
20
20
  self,
21
+ executor_id: str,
21
22
  function_executor_server_factory: FunctionExecutorServerFactory,
22
23
  base_url: str,
23
24
  config_path: Optional[str],
25
+ disable_automatic_function_executor_management: bool,
24
26
  ):
27
+ self._executor_id: str = executor_id
25
28
  self._factory: FunctionExecutorServerFactory = function_executor_server_factory
26
29
  self._base_url: str = base_url
27
30
  self._config_path: Optional[str] = config_path
31
+ self._disable_automatic_function_executor_management: bool = (
32
+ disable_automatic_function_executor_management
33
+ )
28
34
  # The fields below are protected by the lock.
29
35
  self._lock: asyncio.Lock = asyncio.Lock()
30
36
  self._is_shutdown: bool = False
@@ -71,6 +77,9 @@ class TaskRunner:
71
77
  # - Each Function Executor rans at most 1 task concurrently.
72
78
  await state.wait_running_tasks_less(1)
73
79
 
80
+ if self._disable_automatic_function_executor_management:
81
+ return # Disable Function Executor destroy in manual management mode.
82
+
74
83
  if state.function_id_with_version != _function_id_with_version(task):
75
84
  await state.destroy_function_executor()
76
85
  state.function_id_with_version = _function_id_with_version(task)
@@ -81,6 +90,7 @@ class TaskRunner:
81
90
  self, state: FunctionExecutorState, task_input: TaskInput, logger: Any
82
91
  ) -> TaskOutput:
83
92
  runner: SingleTaskRunner = SingleTaskRunner(
93
+ executor_id=self._executor_id,
84
94
  function_executor_state=state,
85
95
  task_input=task_input,
86
96
  function_executor_server_factory=self._factory,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: indexify
3
- Version: 0.3.7
3
+ Version: 0.3.9
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
@@ -22,7 +22,7 @@ Requires-Dist: pydantic (==2.10.4)
22
22
  Requires-Dist: pyyaml (>=6,<7)
23
23
  Requires-Dist: rich (>=13.9.2,<14.0.0)
24
24
  Requires-Dist: structlog (>=24.4.0,<25.0.0)
25
- Requires-Dist: tensorlake (>=0.1.14)
25
+ Requires-Dist: tensorlake (>=0.1.16)
26
26
  Requires-Dist: typer (>=0.12,<0.13)
27
27
  Project-URL: Repository, https://github.com/tensorlakeai/indexify
28
28
  Description-Content-Type: text/markdown
@@ -1,25 +1,25 @@
1
- indexify/cli/cli.py,sha256=uZjcbl41cfBCYrXYp3ggplz3rI7enf-I8pwSYCeNsTo,11502
1
+ indexify/cli/cli.py,sha256=Pk7DwzoaMfHyF-M8CoorBB1iCDUl6Gsh_kf4Dc7SLsM,9551
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=a4f7M_Npfvy5Y-XLqmrPRUdPYvonl4qbK0dDw3EvpZ8,6460
5
- indexify/executor/executor.py,sha256=np6qfwGrCAOmupefoIiGsznJcppZ62vagQuQId4L1Gg,5895
5
+ indexify/executor/executor.py,sha256=YlUr-BNdsRueJx-T3YB9Z-KIFJIiaz26so2C0wLQzrE,6100
6
6
  indexify/executor/function_executor/function_executor.py,sha256=00ILKA4kctsky4v3y26xispJh5Bl07H2VBN9fsaTbOA,5838
7
7
  indexify/executor/function_executor/function_executor_state.py,sha256=_85dpaudYM0sekOqwjMxKGdK7MNQdTGUhHi67sqVHyY,2853
8
8
  indexify/executor/function_executor/health_checker.py,sha256=mYR0WRL-gDFXoyaTBRBnnl9ZfJlL4d-RRe48HEZtU0g,2750
9
9
  indexify/executor/function_executor/invocation_state_client.py,sha256=CfIcVKJZoFMQFOyi3R_dtMgHs5VcGo2V4FKH0or6n80,8586
10
10
  indexify/executor/function_executor/server/client_configuration.py,sha256=gOywMus0cotlX6NKIadEJwvOmBE-LbGE_wvoMi5-HzY,994
11
11
  indexify/executor/function_executor/server/function_executor_server.py,sha256=_DLivLDikupZusRk8gVWDk7fWPT9XjZ4un1yWSlOObs,883
12
- indexify/executor/function_executor/server/function_executor_server_factory.py,sha256=pGbJMQfC5TNvyWOs6VDKdqd2PK5OHQh5_wSDP-E7DbI,1677
12
+ indexify/executor/function_executor/server/function_executor_server_factory.py,sha256=oBEuOwuGsZrvOZsv9v8M4JEtfproirE-cH28XCr0HoY,1739
13
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=asaBLQlY0P5KigA7waX3Lra1aWi8oFeNi7jVj5KvjDI,7764
14
+ indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py,sha256=xm_EL2Gouwi0qAuKsyJVAQJRBZ0VB-NYsWUM4mOi3nQ,4187
15
+ indexify/executor/function_executor/single_task_runner.py,sha256=uHEDCo4ae8npyelKQdkBIHtypuH6fExWShXRFjJoPkY,7882
16
16
  indexify/executor/function_executor/task_input.py,sha256=wSrHR4m0juiGClQyeVdhRC37QzDt6Rrjq-ZXJkfBi9k,584
17
17
  indexify/executor/function_executor/task_output.py,sha256=FLtqpmfhv6faAls0HCzyiZyyOjvENlrslpfl4Mz9JvI,1066
18
18
  indexify/executor/runtime_probes.py,sha256=bo6Dq6AGZpJH099j0DHtVSDEH80tv3j9MXf3VXSx_p8,2182
19
19
  indexify/executor/task_fetcher.py,sha256=hng1moUwRl4bUMwKum8eGgcAd9djU5PJqHT9hxFnhtU,2912
20
- indexify/executor/task_reporter.py,sha256=m0JrXYnBw-wUqeZHdtewCW9H8ojtcphCbvAkGQRPe8g,6640
21
- indexify/executor/task_runner.py,sha256=RSFeJYhQ_agXXPBm8u13HErSUPZGsCGwV1stgS7g258,5035
22
- indexify-0.3.7.dist-info/METADATA,sha256=Rv9YkcMGVCmqgY6IC3tceZOUQRqARrNC-Yd_QcR45ak,1334
23
- indexify-0.3.7.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
24
- indexify-0.3.7.dist-info/entry_points.txt,sha256=GU9wmsgvN7nQw3N2X0PMYn1RSvF6CrhH9RuC2D8d3Gk,53
25
- indexify-0.3.7.dist-info/RECORD,,
20
+ indexify/executor/task_reporter.py,sha256=7VgHA5W1He9Ur0s1bPgXKP75GWhtnIMoUz3_HRPpajE,6882
21
+ indexify/executor/task_runner.py,sha256=w_om0LloMd5cV-K4NrMOJai0vjP7ebsjVEwvP-jDGgg,5500
22
+ indexify-0.3.9.dist-info/METADATA,sha256=2WZDAjnyCJ7imbyvM9fS3MV2hxQ8_3eCDhdZ_3ehKkM,1334
23
+ indexify-0.3.9.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
24
+ indexify-0.3.9.dist-info/entry_points.txt,sha256=GU9wmsgvN7nQw3N2X0PMYn1RSvF6CrhH9RuC2D8d3Gk,53
25
+ indexify-0.3.9.dist-info/RECORD,,