indexify 0.3.7__tar.gz → 0.3.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {indexify-0.3.7 → indexify-0.3.9}/PKG-INFO +2 -2
- {indexify-0.3.7 → indexify-0.3.9}/pyproject.toml +2 -2
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/cli/cli.py +15 -76
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/executor.py +3 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/server/function_executor_server_factory.py +2 -1
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/server/subprocess_function_executor_server_factory.py +2 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/single_task_runner.py +3 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/task_reporter.py +9 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/task_runner.py +10 -0
- {indexify-0.3.7 → indexify-0.3.9}/README.md +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/README.md +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/api_objects.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/downloader.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/function_executor.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/function_executor_state.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/health_checker.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/invocation_state_client.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/server/client_configuration.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/server/function_executor_server.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/server/subprocess_function_executor_server.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/task_input.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/task_output.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/runtime_probes.py +0 -0
- {indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/task_fetcher.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: indexify
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.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.
|
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,7 +1,7 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "indexify"
|
3
3
|
# Incremented if any of the components provided in this packages are updated.
|
4
|
-
version = "0.3.
|
4
|
+
version = "0.3.9"
|
5
5
|
description = "Open Source Indexify components and helper tools"
|
6
6
|
authors = ["Tensorlake Inc. <support@tensorlake.ai>"]
|
7
7
|
license = "Apache 2.0"
|
@@ -24,7 +24,7 @@ grpcio = "1.70.0"
|
|
24
24
|
pydantic = "2.10.4"
|
25
25
|
httpx-sse = "^0.4.0"
|
26
26
|
# Adds function-executor binary and utils lib.
|
27
|
-
tensorlake = ">=0.1.
|
27
|
+
tensorlake = ">=0.1.16"
|
28
28
|
|
29
29
|
# CLI only
|
30
30
|
rich = "^13.9.2"
|
@@ -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
|
-
|
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
|
-
|
321
|
-
|
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
|
|
{indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/single_task_runner.py
RENAMED
@@ -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,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/function_executor.py
RENAMED
File without changes
|
{indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/function_executor_state.py
RENAMED
File without changes
|
File without changes
|
{indexify-0.3.7 → indexify-0.3.9}/src/indexify/executor/function_executor/invocation_state_client.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|