isolate 0.13.4__tar.gz → 0.13.6__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.
Potentially problematic release.
This version of isolate might be problematic. Click here for more details.
- {isolate-0.13.4 → isolate-0.13.6}/PKG-INFO +1 -1
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/_isolate_version.py +2 -2
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/_base.py +0 -2
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/agent.py +13 -1
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/definitions/server.proto +25 -1
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/definitions/server_pb2.py +14 -4
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/definitions/server_pb2.pyi +71 -2
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/definitions/server_pb2_grpc.py +88 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/server.py +103 -43
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate.egg-info/PKG-INFO +1 -1
- {isolate-0.13.4 → isolate-0.13.6}/tests/test_server.py +29 -7
- {isolate-0.13.4 → isolate-0.13.6}/.github/workflows/release.yml +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/.github/workflows/test.yml +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/.gitignore +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/.pre-commit-config.yaml +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/LICENSE +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/README.md +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/pyproject.toml +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/setup.cfg +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/_version.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/_base.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/common.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/conda.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/container.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/local.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/pyenv.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/remote.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/settings.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/backends/virtualenv.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/common/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/common/timestamp.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/_local/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/_local/_base.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/_local/agent_startup.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/common.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/configuration.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/agent.proto +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/agent_pb2.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/agent_pb2.pyi +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/common.proto +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/common_pb2.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/common_pb2.pyi +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/common_pb2_grpc.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/interface.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/ipc/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/ipc/_base.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/ipc/agent.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/logger.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/logs.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/py.typed +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/registry.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/definitions/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/health/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/health/health.proto +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/health/health_pb2.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/health/health_pb2.pyi +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/health/health_pb2_grpc.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/health_server.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate/server/interface.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate.egg-info/SOURCES.txt +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate.egg-info/dependency_links.txt +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate.egg-info/entry_points.txt +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate.egg-info/requires.txt +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/src/isolate.egg-info/top_level.txt +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tests/__init__.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tests/conftest.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tests/test_backends.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tests/test_concurrency.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tests/test_connections.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tests/test_isolate.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tests/test_log.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tests/test_serialization.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tools/Dockerfile +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tools/agent_requirements.txt +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tools/protobuf-requirements.txt +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tools/regen_grpc.py +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tools/requirements.txt +0 -0
- {isolate-0.13.4 → isolate-0.13.6}/tools/test_agent_requirements.txt +0 -0
|
@@ -16,7 +16,6 @@ from isolate.connections.common import serialize_object
|
|
|
16
16
|
from isolate.connections.grpc import agent, definitions
|
|
17
17
|
from isolate.connections.grpc.configuration import get_default_options
|
|
18
18
|
from isolate.connections.grpc.interface import from_grpc
|
|
19
|
-
from isolate.logger import logger
|
|
20
19
|
from isolate.logs import LogLevel, LogSource
|
|
21
20
|
|
|
22
21
|
|
|
@@ -149,5 +148,4 @@ class LocalPythonGRPC(PythonExecutionBase[str], GRPCExecutionBase):
|
|
|
149
148
|
]
|
|
150
149
|
|
|
151
150
|
def handle_agent_log(self, line: str, level: LogLevel, source: LogSource) -> None:
|
|
152
|
-
logger.log(level, line, source)
|
|
153
151
|
self.log(line, level=level, source=source)
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
# agent-requires: isolate[server]
|
|
2
|
+
"""
|
|
3
|
+
This file contains the implementation of the gRPC agent. The agent is a
|
|
4
|
+
separate process that is responsible for running the user code in a
|
|
5
|
+
sandboxed environment.
|
|
6
|
+
|
|
7
|
+
This file is referenced by the latest version of the `isolate` package
|
|
8
|
+
but then runs it in the context of the frozen agent built environment.
|
|
9
|
+
"""
|
|
2
10
|
|
|
3
11
|
from __future__ import annotations
|
|
4
12
|
|
|
@@ -17,7 +25,11 @@ from typing import (
|
|
|
17
25
|
import grpc
|
|
18
26
|
from grpc import ServicerContext, StatusCode
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
try:
|
|
29
|
+
from isolate import __version__ as agent_version
|
|
30
|
+
except ImportError:
|
|
31
|
+
agent_version = "UNKNOWN"
|
|
32
|
+
|
|
21
33
|
from isolate.backends.common import sha256_digest_of
|
|
22
34
|
from isolate.connections.common import SerializationError, serialize_object
|
|
23
35
|
from isolate.connections.grpc import definitions
|
|
@@ -10,6 +10,12 @@ service Isolate {
|
|
|
10
10
|
|
|
11
11
|
// Submit a function to be run without waiting for results.
|
|
12
12
|
rpc Submit (SubmitRequest) returns (SubmitResponse) {}
|
|
13
|
+
|
|
14
|
+
// List running tasks
|
|
15
|
+
rpc List (ListRequest) returns (ListResponse) {}
|
|
16
|
+
|
|
17
|
+
// Cancel a running task
|
|
18
|
+
rpc Cancel (CancelRequest) returns (CancelResponse) {}
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
message BoundFunction {
|
|
@@ -33,5 +39,23 @@ message SubmitRequest {
|
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
message SubmitResponse {
|
|
36
|
-
|
|
42
|
+
string task_id = 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
message ListRequest {
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
message TaskInfo {
|
|
49
|
+
string task_id = 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
message ListResponse {
|
|
53
|
+
repeated TaskInfo tasks = 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
message CancelRequest {
|
|
57
|
+
string task_id = 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
message CancelResponse {
|
|
37
61
|
}
|
|
@@ -16,7 +16,7 @@ from isolate.connections.grpc.definitions import common_pb2 as common__pb2
|
|
|
16
16
|
from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cserver.proto\x1a\x0c\x63ommon.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x9d\x01\n\rBoundFunction\x12,\n\x0c\x65nvironments\x18\x01 \x03(\x0b\x32\x16.EnvironmentDefinition\x12#\n\x08\x66unction\x18\x02 \x01(\x0b\x32\x11.SerializedObject\x12*\n\nsetup_func\x18\x03 \x01(\x0b\x32\x11.SerializedObjectH\x00\x88\x01\x01\x42\r\n\x0b_setup_func\"d\n\x15\x45nvironmentDefinition\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12.\n\rconfiguration\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\r\n\x05\x66orce\x18\x03 \x01(\x08\"1\n\rSubmitRequest\x12 \n\x08\x66unction\x18\x01 \x01(\x0b\x32\x0e.BoundFunction\"\x10\n\
|
|
19
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cserver.proto\x1a\x0c\x63ommon.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x9d\x01\n\rBoundFunction\x12,\n\x0c\x65nvironments\x18\x01 \x03(\x0b\x32\x16.EnvironmentDefinition\x12#\n\x08\x66unction\x18\x02 \x01(\x0b\x32\x11.SerializedObject\x12*\n\nsetup_func\x18\x03 \x01(\x0b\x32\x11.SerializedObjectH\x00\x88\x01\x01\x42\r\n\x0b_setup_func\"d\n\x15\x45nvironmentDefinition\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12.\n\rconfiguration\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\r\n\x05\x66orce\x18\x03 \x01(\x08\"1\n\rSubmitRequest\x12 \n\x08\x66unction\x18\x01 \x01(\x0b\x32\x0e.BoundFunction\"!\n\x0eSubmitResponse\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"\r\n\x0bListRequest\"\x1b\n\x08TaskInfo\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"(\n\x0cListResponse\x12\x18\n\x05tasks\x18\x01 \x03(\x0b\x32\t.TaskInfo\" \n\rCancelRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"\x10\n\x0e\x43\x61ncelResponse2\xb8\x01\n\x07Isolate\x12,\n\x03Run\x12\x0e.BoundFunction\x1a\x11.PartialRunResult\"\x00\x30\x01\x12+\n\x06Submit\x12\x0e.SubmitRequest\x1a\x0f.SubmitResponse\"\x00\x12%\n\x04List\x12\x0c.ListRequest\x1a\r.ListResponse\"\x00\x12+\n\x06\x43\x61ncel\x12\x0e.CancelRequest\x1a\x0f.CancelResponse\"\x00\x62\x06proto3')
|
|
20
20
|
|
|
21
21
|
_globals = globals()
|
|
22
22
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -30,7 +30,17 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
30
30
|
_globals['_SUBMITREQUEST']._serialized_start=322
|
|
31
31
|
_globals['_SUBMITREQUEST']._serialized_end=371
|
|
32
32
|
_globals['_SUBMITRESPONSE']._serialized_start=373
|
|
33
|
-
_globals['_SUBMITRESPONSE']._serialized_end=
|
|
34
|
-
_globals['
|
|
35
|
-
_globals['
|
|
33
|
+
_globals['_SUBMITRESPONSE']._serialized_end=406
|
|
34
|
+
_globals['_LISTREQUEST']._serialized_start=408
|
|
35
|
+
_globals['_LISTREQUEST']._serialized_end=421
|
|
36
|
+
_globals['_TASKINFO']._serialized_start=423
|
|
37
|
+
_globals['_TASKINFO']._serialized_end=450
|
|
38
|
+
_globals['_LISTRESPONSE']._serialized_start=452
|
|
39
|
+
_globals['_LISTRESPONSE']._serialized_end=492
|
|
40
|
+
_globals['_CANCELREQUEST']._serialized_start=494
|
|
41
|
+
_globals['_CANCELREQUEST']._serialized_end=526
|
|
42
|
+
_globals['_CANCELRESPONSE']._serialized_start=528
|
|
43
|
+
_globals['_CANCELRESPONSE']._serialized_end=544
|
|
44
|
+
_globals['_ISOLATE']._serialized_start=547
|
|
45
|
+
_globals['_ISOLATE']._serialized_end=731
|
|
36
46
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -88,12 +88,81 @@ global___SubmitRequest = SubmitRequest
|
|
|
88
88
|
|
|
89
89
|
@typing.final
|
|
90
90
|
class SubmitResponse(google.protobuf.message.Message):
|
|
91
|
-
"""Reserved for future use."""
|
|
92
|
-
|
|
93
91
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
94
92
|
|
|
93
|
+
TASK_ID_FIELD_NUMBER: builtins.int
|
|
94
|
+
task_id: builtins.str
|
|
95
95
|
def __init__(
|
|
96
96
|
self,
|
|
97
|
+
*,
|
|
98
|
+
task_id: builtins.str = ...,
|
|
97
99
|
) -> None: ...
|
|
100
|
+
def ClearField(self, field_name: typing.Literal["task_id", b"task_id"]) -> None: ...
|
|
98
101
|
|
|
99
102
|
global___SubmitResponse = SubmitResponse
|
|
103
|
+
|
|
104
|
+
@typing.final
|
|
105
|
+
class ListRequest(google.protobuf.message.Message):
|
|
106
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
107
|
+
|
|
108
|
+
def __init__(
|
|
109
|
+
self,
|
|
110
|
+
) -> None: ...
|
|
111
|
+
|
|
112
|
+
global___ListRequest = ListRequest
|
|
113
|
+
|
|
114
|
+
@typing.final
|
|
115
|
+
class TaskInfo(google.protobuf.message.Message):
|
|
116
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
117
|
+
|
|
118
|
+
TASK_ID_FIELD_NUMBER: builtins.int
|
|
119
|
+
task_id: builtins.str
|
|
120
|
+
def __init__(
|
|
121
|
+
self,
|
|
122
|
+
*,
|
|
123
|
+
task_id: builtins.str = ...,
|
|
124
|
+
) -> None: ...
|
|
125
|
+
def ClearField(self, field_name: typing.Literal["task_id", b"task_id"]) -> None: ...
|
|
126
|
+
|
|
127
|
+
global___TaskInfo = TaskInfo
|
|
128
|
+
|
|
129
|
+
@typing.final
|
|
130
|
+
class ListResponse(google.protobuf.message.Message):
|
|
131
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
132
|
+
|
|
133
|
+
TASKS_FIELD_NUMBER: builtins.int
|
|
134
|
+
@property
|
|
135
|
+
def tasks(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___TaskInfo]: ...
|
|
136
|
+
def __init__(
|
|
137
|
+
self,
|
|
138
|
+
*,
|
|
139
|
+
tasks: collections.abc.Iterable[global___TaskInfo] | None = ...,
|
|
140
|
+
) -> None: ...
|
|
141
|
+
def ClearField(self, field_name: typing.Literal["tasks", b"tasks"]) -> None: ...
|
|
142
|
+
|
|
143
|
+
global___ListResponse = ListResponse
|
|
144
|
+
|
|
145
|
+
@typing.final
|
|
146
|
+
class CancelRequest(google.protobuf.message.Message):
|
|
147
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
148
|
+
|
|
149
|
+
TASK_ID_FIELD_NUMBER: builtins.int
|
|
150
|
+
task_id: builtins.str
|
|
151
|
+
def __init__(
|
|
152
|
+
self,
|
|
153
|
+
*,
|
|
154
|
+
task_id: builtins.str = ...,
|
|
155
|
+
) -> None: ...
|
|
156
|
+
def ClearField(self, field_name: typing.Literal["task_id", b"task_id"]) -> None: ...
|
|
157
|
+
|
|
158
|
+
global___CancelRequest = CancelRequest
|
|
159
|
+
|
|
160
|
+
@typing.final
|
|
161
|
+
class CancelResponse(google.protobuf.message.Message):
|
|
162
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
163
|
+
|
|
164
|
+
def __init__(
|
|
165
|
+
self,
|
|
166
|
+
) -> None: ...
|
|
167
|
+
|
|
168
|
+
global___CancelResponse = CancelResponse
|
|
@@ -50,6 +50,16 @@ class IsolateStub(object):
|
|
|
50
50
|
request_serializer=server__pb2.SubmitRequest.SerializeToString,
|
|
51
51
|
response_deserializer=server__pb2.SubmitResponse.FromString,
|
|
52
52
|
_registered_method=True)
|
|
53
|
+
self.List = channel.unary_unary(
|
|
54
|
+
'/Isolate/List',
|
|
55
|
+
request_serializer=server__pb2.ListRequest.SerializeToString,
|
|
56
|
+
response_deserializer=server__pb2.ListResponse.FromString,
|
|
57
|
+
_registered_method=True)
|
|
58
|
+
self.Cancel = channel.unary_unary(
|
|
59
|
+
'/Isolate/Cancel',
|
|
60
|
+
request_serializer=server__pb2.CancelRequest.SerializeToString,
|
|
61
|
+
response_deserializer=server__pb2.CancelResponse.FromString,
|
|
62
|
+
_registered_method=True)
|
|
53
63
|
|
|
54
64
|
|
|
55
65
|
class IsolateServicer(object):
|
|
@@ -70,6 +80,20 @@ class IsolateServicer(object):
|
|
|
70
80
|
context.set_details('Method not implemented!')
|
|
71
81
|
raise NotImplementedError('Method not implemented!')
|
|
72
82
|
|
|
83
|
+
def List(self, request, context):
|
|
84
|
+
"""List running tasks
|
|
85
|
+
"""
|
|
86
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
87
|
+
context.set_details('Method not implemented!')
|
|
88
|
+
raise NotImplementedError('Method not implemented!')
|
|
89
|
+
|
|
90
|
+
def Cancel(self, request, context):
|
|
91
|
+
"""Cancel a running task
|
|
92
|
+
"""
|
|
93
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
94
|
+
context.set_details('Method not implemented!')
|
|
95
|
+
raise NotImplementedError('Method not implemented!')
|
|
96
|
+
|
|
73
97
|
|
|
74
98
|
def add_IsolateServicer_to_server(servicer, server):
|
|
75
99
|
rpc_method_handlers = {
|
|
@@ -83,6 +107,16 @@ def add_IsolateServicer_to_server(servicer, server):
|
|
|
83
107
|
request_deserializer=server__pb2.SubmitRequest.FromString,
|
|
84
108
|
response_serializer=server__pb2.SubmitResponse.SerializeToString,
|
|
85
109
|
),
|
|
110
|
+
'List': grpc.unary_unary_rpc_method_handler(
|
|
111
|
+
servicer.List,
|
|
112
|
+
request_deserializer=server__pb2.ListRequest.FromString,
|
|
113
|
+
response_serializer=server__pb2.ListResponse.SerializeToString,
|
|
114
|
+
),
|
|
115
|
+
'Cancel': grpc.unary_unary_rpc_method_handler(
|
|
116
|
+
servicer.Cancel,
|
|
117
|
+
request_deserializer=server__pb2.CancelRequest.FromString,
|
|
118
|
+
response_serializer=server__pb2.CancelResponse.SerializeToString,
|
|
119
|
+
),
|
|
86
120
|
}
|
|
87
121
|
generic_handler = grpc.method_handlers_generic_handler(
|
|
88
122
|
'Isolate', rpc_method_handlers)
|
|
@@ -147,3 +181,57 @@ class Isolate(object):
|
|
|
147
181
|
timeout,
|
|
148
182
|
metadata,
|
|
149
183
|
_registered_method=True)
|
|
184
|
+
|
|
185
|
+
@staticmethod
|
|
186
|
+
def List(request,
|
|
187
|
+
target,
|
|
188
|
+
options=(),
|
|
189
|
+
channel_credentials=None,
|
|
190
|
+
call_credentials=None,
|
|
191
|
+
insecure=False,
|
|
192
|
+
compression=None,
|
|
193
|
+
wait_for_ready=None,
|
|
194
|
+
timeout=None,
|
|
195
|
+
metadata=None):
|
|
196
|
+
return grpc.experimental.unary_unary(
|
|
197
|
+
request,
|
|
198
|
+
target,
|
|
199
|
+
'/Isolate/List',
|
|
200
|
+
server__pb2.ListRequest.SerializeToString,
|
|
201
|
+
server__pb2.ListResponse.FromString,
|
|
202
|
+
options,
|
|
203
|
+
channel_credentials,
|
|
204
|
+
insecure,
|
|
205
|
+
call_credentials,
|
|
206
|
+
compression,
|
|
207
|
+
wait_for_ready,
|
|
208
|
+
timeout,
|
|
209
|
+
metadata,
|
|
210
|
+
_registered_method=True)
|
|
211
|
+
|
|
212
|
+
@staticmethod
|
|
213
|
+
def Cancel(request,
|
|
214
|
+
target,
|
|
215
|
+
options=(),
|
|
216
|
+
channel_credentials=None,
|
|
217
|
+
call_credentials=None,
|
|
218
|
+
insecure=False,
|
|
219
|
+
compression=None,
|
|
220
|
+
wait_for_ready=None,
|
|
221
|
+
timeout=None,
|
|
222
|
+
metadata=None):
|
|
223
|
+
return grpc.experimental.unary_unary(
|
|
224
|
+
request,
|
|
225
|
+
target,
|
|
226
|
+
'/Isolate/Cancel',
|
|
227
|
+
server__pb2.CancelRequest.SerializeToString,
|
|
228
|
+
server__pb2.CancelResponse.FromString,
|
|
229
|
+
options,
|
|
230
|
+
channel_credentials,
|
|
231
|
+
insecure,
|
|
232
|
+
call_credentials,
|
|
233
|
+
compression,
|
|
234
|
+
wait_for_ready,
|
|
235
|
+
timeout,
|
|
236
|
+
metadata,
|
|
237
|
+
_registered_method=True)
|
|
@@ -4,12 +4,12 @@ import os
|
|
|
4
4
|
import threading
|
|
5
5
|
import time
|
|
6
6
|
import traceback
|
|
7
|
+
import uuid
|
|
7
8
|
from collections import defaultdict
|
|
8
9
|
from concurrent import futures
|
|
9
10
|
from concurrent.futures import ThreadPoolExecutor
|
|
10
11
|
from contextlib import ExitStack, contextmanager
|
|
11
12
|
from dataclasses import dataclass, field, replace
|
|
12
|
-
from functools import partial
|
|
13
13
|
from queue import Empty as QueueEmpty
|
|
14
14
|
from queue import Queue
|
|
15
15
|
from typing import Any, Callable, Iterator, cast
|
|
@@ -26,6 +26,7 @@ from isolate.backends.local import LocalPythonEnvironment
|
|
|
26
26
|
from isolate.backends.virtualenv import VirtualPythonEnvironment
|
|
27
27
|
from isolate.connections.grpc import AgentError, LocalPythonGRPC
|
|
28
28
|
from isolate.connections.grpc.configuration import get_default_options
|
|
29
|
+
from isolate.logger import logger
|
|
29
30
|
from isolate.logs import Log, LogLevel, LogSource
|
|
30
31
|
from isolate.server import definitions, health
|
|
31
32
|
from isolate.server.health_server import HealthServicer
|
|
@@ -114,11 +115,11 @@ class BridgeManager:
|
|
|
114
115
|
self,
|
|
115
116
|
connection: LocalPythonGRPC,
|
|
116
117
|
queue: Queue,
|
|
117
|
-
) -> Iterator[
|
|
118
|
+
) -> Iterator[RunnerAgent]:
|
|
118
119
|
agent = self._allocate_new_agent(connection, queue)
|
|
119
120
|
|
|
120
121
|
try:
|
|
121
|
-
yield agent
|
|
122
|
+
yield agent
|
|
122
123
|
finally:
|
|
123
124
|
self._cache_agent(connection, agent)
|
|
124
125
|
|
|
@@ -165,19 +166,34 @@ class BridgeManager:
|
|
|
165
166
|
agent.terminate()
|
|
166
167
|
|
|
167
168
|
|
|
169
|
+
@dataclass
|
|
170
|
+
class RunTask:
|
|
171
|
+
request: definitions.BoundFunction
|
|
172
|
+
future: futures.Future | None = None
|
|
173
|
+
agent: RunnerAgent | None = None
|
|
174
|
+
|
|
175
|
+
def cancel(self):
|
|
176
|
+
while True:
|
|
177
|
+
self.future.cancel()
|
|
178
|
+
if self.agent:
|
|
179
|
+
self.agent.terminate()
|
|
180
|
+
try:
|
|
181
|
+
self.future.exception(timeout=0.1)
|
|
182
|
+
return
|
|
183
|
+
except futures.TimeoutError:
|
|
184
|
+
pass
|
|
185
|
+
|
|
186
|
+
|
|
168
187
|
@dataclass
|
|
169
188
|
class IsolateServicer(definitions.IsolateServicer):
|
|
170
189
|
bridge_manager: BridgeManager
|
|
171
190
|
default_settings: IsolateSettings = field(default_factory=IsolateSettings)
|
|
172
|
-
background_tasks:
|
|
191
|
+
background_tasks: dict[str, RunTask] = field(default_factory=dict)
|
|
173
192
|
|
|
174
|
-
def
|
|
175
|
-
self,
|
|
176
|
-
request: definitions.BoundFunction,
|
|
177
|
-
) -> Iterator[definitions.PartialRunResult]:
|
|
193
|
+
def _run_task(self, task: RunTask) -> Iterator[definitions.PartialRunResult]:
|
|
178
194
|
messages: Queue[definitions.PartialRunResult] = Queue()
|
|
179
195
|
environments = []
|
|
180
|
-
for env in request.environments:
|
|
196
|
+
for env in task.request.environments:
|
|
181
197
|
try:
|
|
182
198
|
environments.append((env.force, from_grpc(env)))
|
|
183
199
|
except ValueError:
|
|
@@ -191,10 +207,11 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
191
207
|
StatusCode.INVALID_ARGUMENT,
|
|
192
208
|
)
|
|
193
209
|
|
|
210
|
+
log_handler = LogHandler(messages)
|
|
194
211
|
run_settings = replace(
|
|
195
212
|
self.default_settings,
|
|
196
|
-
log_hook=
|
|
197
|
-
serialization_method=request.function.method,
|
|
213
|
+
log_hook=log_handler.handle,
|
|
214
|
+
serialization_method=task.request.function.method,
|
|
198
215
|
)
|
|
199
216
|
|
|
200
217
|
for _, environment in environments:
|
|
@@ -243,28 +260,28 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
243
260
|
extra_inheritance_paths=inheritance_paths,
|
|
244
261
|
)
|
|
245
262
|
|
|
246
|
-
with self.bridge_manager.establish(connection, queue=messages) as
|
|
247
|
-
|
|
248
|
-
queue,
|
|
249
|
-
):
|
|
263
|
+
with self.bridge_manager.establish(connection, queue=messages) as agent:
|
|
264
|
+
task.agent = agent
|
|
250
265
|
function_call = definitions.FunctionCall(
|
|
251
|
-
function=request.function,
|
|
252
|
-
setup_func=request.setup_func,
|
|
266
|
+
function=task.request.function,
|
|
267
|
+
setup_func=task.request.setup_func,
|
|
253
268
|
)
|
|
254
|
-
if not request.HasField("setup_func"):
|
|
269
|
+
if not task.request.HasField("setup_func"):
|
|
255
270
|
function_call.ClearField("setup_func")
|
|
256
271
|
|
|
257
272
|
future = local_pool.submit(
|
|
258
273
|
_proxy_to_queue,
|
|
259
|
-
queue=
|
|
260
|
-
bridge=
|
|
274
|
+
queue=agent.message_queue,
|
|
275
|
+
bridge=agent.stub,
|
|
261
276
|
input=function_call,
|
|
262
277
|
)
|
|
263
278
|
|
|
264
279
|
# Unlike above; we are not interested in the result value of future
|
|
265
280
|
# here, since it will be already transferred to other side without
|
|
266
281
|
# us even seeing (through the queue).
|
|
267
|
-
yield from self.watch_queue_until_completed(
|
|
282
|
+
yield from self.watch_queue_until_completed(
|
|
283
|
+
agent.message_queue, future.done
|
|
284
|
+
)
|
|
268
285
|
|
|
269
286
|
# But we still have to check whether there were any errors raised
|
|
270
287
|
# during the execution, and handle them accordingly.
|
|
@@ -292,14 +309,8 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
292
309
|
StatusCode.UNKNOWN,
|
|
293
310
|
)
|
|
294
311
|
|
|
295
|
-
def
|
|
296
|
-
self
|
|
297
|
-
bound_function: definitions.BoundFunction,
|
|
298
|
-
) -> None:
|
|
299
|
-
try:
|
|
300
|
-
for _ in self._run_function(bound_function):
|
|
301
|
-
pass
|
|
302
|
-
except GRPCException:
|
|
312
|
+
def _run_task_in_background(self, task: RunTask) -> None:
|
|
313
|
+
for _ in self._run_task(task):
|
|
303
314
|
pass
|
|
304
315
|
|
|
305
316
|
def Submit(
|
|
@@ -307,13 +318,24 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
307
318
|
request: definitions.SubmitRequest,
|
|
308
319
|
context: ServicerContext,
|
|
309
320
|
) -> definitions.SubmitResponse:
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
321
|
+
task = RunTask(request=request.function)
|
|
322
|
+
task.future = RUNNER_THREAD_POOL.submit(
|
|
323
|
+
self._run_task_in_background,
|
|
324
|
+
task,
|
|
313
325
|
)
|
|
314
|
-
|
|
326
|
+
task_id = str(uuid.uuid4())
|
|
327
|
+
|
|
328
|
+
print(f"Submitted a task {task_id}")
|
|
329
|
+
|
|
330
|
+
self.background_tasks[task_id] = task
|
|
315
331
|
|
|
316
|
-
|
|
332
|
+
def _callback(_):
|
|
333
|
+
print(f"Task {task_id} finished")
|
|
334
|
+
self.background_tasks.pop(task_id, None)
|
|
335
|
+
|
|
336
|
+
task.future.add_done_callback(_callback)
|
|
337
|
+
|
|
338
|
+
return definitions.SubmitResponse(task_id=task_id)
|
|
317
339
|
|
|
318
340
|
def Run(
|
|
319
341
|
self,
|
|
@@ -321,7 +343,7 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
321
343
|
context: ServicerContext,
|
|
322
344
|
) -> Iterator[definitions.PartialRunResult]:
|
|
323
345
|
try:
|
|
324
|
-
yield from self.
|
|
346
|
+
yield from self._run_task(RunTask(request=request))
|
|
325
347
|
except GRPCException as exc:
|
|
326
348
|
return self.abort_with_msg(
|
|
327
349
|
exc.message,
|
|
@@ -329,6 +351,32 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
329
351
|
code=exc.code,
|
|
330
352
|
)
|
|
331
353
|
|
|
354
|
+
def List(
|
|
355
|
+
self,
|
|
356
|
+
request: definitions.ListRequest,
|
|
357
|
+
context: ServicerContext,
|
|
358
|
+
) -> definitions.ListResponse:
|
|
359
|
+
return definitions.ListResponse(
|
|
360
|
+
tasks=[
|
|
361
|
+
definitions.TaskInfo(task_id=task_id)
|
|
362
|
+
for task_id in self.background_tasks.keys()
|
|
363
|
+
]
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
def Cancel(
|
|
367
|
+
self,
|
|
368
|
+
request: definitions.CancelRequest,
|
|
369
|
+
context: ServicerContext,
|
|
370
|
+
) -> definitions.CancelResponse:
|
|
371
|
+
task_id = request.task_id
|
|
372
|
+
|
|
373
|
+
print(f"Canceling task {task_id}")
|
|
374
|
+
task = self.background_tasks.get(task_id)
|
|
375
|
+
if task is not None:
|
|
376
|
+
task.cancel()
|
|
377
|
+
|
|
378
|
+
return definitions.CancelResponse()
|
|
379
|
+
|
|
332
380
|
def watch_queue_until_completed(
|
|
333
381
|
self, queue: Queue, is_completed: Callable[[], bool]
|
|
334
382
|
) -> Iterator[definitions.PartialRunResult]:
|
|
@@ -380,6 +428,10 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
380
428
|
context.set_details(message)
|
|
381
429
|
return None
|
|
382
430
|
|
|
431
|
+
def cancel_tasks(self):
|
|
432
|
+
for task in self.background_tasks.values():
|
|
433
|
+
task.cancel()
|
|
434
|
+
|
|
383
435
|
|
|
384
436
|
def _proxy_to_queue(
|
|
385
437
|
queue: Queue,
|
|
@@ -390,14 +442,22 @@ def _proxy_to_queue(
|
|
|
390
442
|
queue.put_nowait(message)
|
|
391
443
|
|
|
392
444
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
445
|
+
@dataclass
|
|
446
|
+
class LogHandler:
|
|
447
|
+
messages: Queue
|
|
448
|
+
|
|
449
|
+
def handle(self, log: Log) -> None:
|
|
450
|
+
logger.log(log.level, log.message, source=log.source)
|
|
451
|
+
self._add_log_to_queue(log)
|
|
452
|
+
|
|
453
|
+
def _add_log_to_queue(self, log: Log) -> None:
|
|
454
|
+
grpc_log = cast(definitions.Log, to_grpc(log))
|
|
455
|
+
grpc_result = definitions.PartialRunResult(
|
|
456
|
+
is_complete=False,
|
|
457
|
+
logs=[grpc_log],
|
|
458
|
+
result=None,
|
|
459
|
+
)
|
|
460
|
+
self.messages.put_nowait(grpc_result)
|
|
401
461
|
|
|
402
462
|
|
|
403
463
|
def main() -> None:
|
|
@@ -65,11 +65,7 @@ def make_server(tmp_path):
|
|
|
65
65
|
yield Stubs(isolate_stub=isolate_stub, health_stub=health_stub)
|
|
66
66
|
finally:
|
|
67
67
|
server.stop(None)
|
|
68
|
-
|
|
69
|
-
if task.done():
|
|
70
|
-
task.result()
|
|
71
|
-
else:
|
|
72
|
-
print("leaking background task", task)
|
|
68
|
+
servicer.cancel_tasks()
|
|
73
69
|
|
|
74
70
|
|
|
75
71
|
@pytest.fixture
|
|
@@ -217,7 +213,7 @@ def test_server_builder_error(stub: definitions.IsolateStub, monkeypatch: Any) -
|
|
|
217
213
|
assert "Failure during 'pip install': Command" in exc.value.details()
|
|
218
214
|
|
|
219
215
|
raw_logs = [log.message for log in build_logs]
|
|
220
|
-
assert "ERROR: Invalid requirement: '$$$$'" in raw_logs
|
|
216
|
+
assert any("ERROR: Invalid requirement: '$$$$'" in raw_log for raw_log in raw_logs)
|
|
221
217
|
|
|
222
218
|
|
|
223
219
|
def test_user_logs_immediate(stub: definitions.IsolateStub, monkeypatch: Any) -> None:
|
|
@@ -402,7 +398,7 @@ def test_agent_show_logs_from_agent_requirements(
|
|
|
402
398
|
assert "Failure during 'pip install': Command" in exc.value.details()
|
|
403
399
|
|
|
404
400
|
raw_logs = [log.message for log in build_logs]
|
|
405
|
-
assert "ERROR: Invalid requirement: '$$$$'" in raw_logs
|
|
401
|
+
assert any("ERROR: Invalid requirement: '$$$$'" in raw_log for raw_log in raw_logs)
|
|
406
402
|
|
|
407
403
|
|
|
408
404
|
def test_bridge_connection_reuse(
|
|
@@ -697,3 +693,29 @@ def test_server_submit(
|
|
|
697
693
|
stub.Submit(request)
|
|
698
694
|
time.sleep(5)
|
|
699
695
|
assert "completed" in file.read_text()
|
|
696
|
+
assert not list(stub.List(definitions.ListRequest()).tasks)
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
def myserver():
|
|
700
|
+
import time
|
|
701
|
+
|
|
702
|
+
while True:
|
|
703
|
+
print("running")
|
|
704
|
+
time.sleep(1)
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
def test_server_submit_server(
|
|
708
|
+
stub: definitions.IsolateStub,
|
|
709
|
+
monkeypatch: Any,
|
|
710
|
+
) -> None:
|
|
711
|
+
inherit_from_local(monkeypatch)
|
|
712
|
+
|
|
713
|
+
request = definitions.SubmitRequest(function=prepare_request(myserver))
|
|
714
|
+
task_id = stub.Submit(request).task_id
|
|
715
|
+
|
|
716
|
+
tasks = [task.task_id for task in stub.List(definitions.ListRequest()).tasks]
|
|
717
|
+
assert task_id in tasks
|
|
718
|
+
|
|
719
|
+
stub.Cancel(definitions.CancelRequest(task_id=task_id))
|
|
720
|
+
|
|
721
|
+
assert not list(stub.List(definitions.ListRequest()).tasks)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{isolate-0.13.4 → isolate-0.13.6}/src/isolate/connections/grpc/definitions/common_pb2_grpc.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|