isolate 0.13.10__py3-none-any.whl → 0.14.1__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.
Potentially problematic release.
This version of isolate might be problematic. Click here for more details.
- isolate/_isolate_version.py +2 -2
- isolate/connections/grpc/definitions/agent_pb2.pyi +10 -8
- isolate/connections/grpc/definitions/common_pb2.pyi +11 -14
- isolate/logger.py +32 -14
- isolate/server/definitions/server.proto +18 -0
- isolate/server/definitions/server_pb2.py +26 -16
- isolate/server/definitions/server_pb2.pyi +96 -26
- isolate/server/definitions/server_pb2_grpc.py +44 -0
- isolate/server/health/health_pb2.pyi +4 -5
- isolate/server/server.py +103 -28
- {isolate-0.13.10.dist-info → isolate-0.14.1.dist-info}/METADATA +1 -1
- {isolate-0.13.10.dist-info → isolate-0.14.1.dist-info}/RECORD +16 -16
- {isolate-0.13.10.dist-info → isolate-0.14.1.dist-info}/WHEEL +1 -1
- {isolate-0.13.10.dist-info → isolate-0.14.1.dist-info}/LICENSE +0 -0
- {isolate-0.13.10.dist-info → isolate-0.14.1.dist-info}/entry_points.txt +0 -0
- {isolate-0.13.10.dist-info → isolate-0.14.1.dist-info}/top_level.txt +0 -0
isolate/_isolate_version.py
CHANGED
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
@generated by mypy-protobuf. Do not edit manually!
|
|
3
3
|
isort:skip_file
|
|
4
4
|
"""
|
|
5
|
-
|
|
6
5
|
import builtins
|
|
7
6
|
from isolate.connections.grpc.definitions import common_pb2
|
|
8
7
|
import google.protobuf.descriptor
|
|
9
8
|
import google.protobuf.message
|
|
10
|
-
import
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
if sys.version_info >= (3, 8):
|
|
12
|
+
import typing as typing_extensions
|
|
13
|
+
else:
|
|
14
|
+
import typing_extensions
|
|
11
15
|
|
|
12
16
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
|
13
17
|
|
|
14
|
-
@
|
|
18
|
+
@typing_extensions.final
|
|
15
19
|
class FunctionCall(google.protobuf.message.Message):
|
|
16
20
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
17
21
|
|
|
@@ -20,7 +24,6 @@ class FunctionCall(google.protobuf.message.Message):
|
|
|
20
24
|
@property
|
|
21
25
|
def function(self) -> common_pb2.SerializedObject:
|
|
22
26
|
"""The function to execute and return the results to."""
|
|
23
|
-
|
|
24
27
|
@property
|
|
25
28
|
def setup_func(self) -> common_pb2.SerializedObject:
|
|
26
29
|
"""Optionally the setup function which will be passed
|
|
@@ -28,15 +31,14 @@ class FunctionCall(google.protobuf.message.Message):
|
|
|
28
31
|
has to be an idempotent step since the result for
|
|
29
32
|
this executable will be cached.
|
|
30
33
|
"""
|
|
31
|
-
|
|
32
34
|
def __init__(
|
|
33
35
|
self,
|
|
34
36
|
*,
|
|
35
37
|
function: common_pb2.SerializedObject | None = ...,
|
|
36
38
|
setup_func: common_pb2.SerializedObject | None = ...,
|
|
37
39
|
) -> None: ...
|
|
38
|
-
def HasField(self, field_name:
|
|
39
|
-
def ClearField(self, field_name:
|
|
40
|
-
def WhichOneof(self, oneof_group:
|
|
40
|
+
def HasField(self, field_name: typing_extensions.Literal["_setup_func", b"_setup_func", "function", b"function", "setup_func", b"setup_func"]) -> builtins.bool: ...
|
|
41
|
+
def ClearField(self, field_name: typing_extensions.Literal["_setup_func", b"_setup_func", "function", b"function", "setup_func", b"setup_func"]) -> None: ...
|
|
42
|
+
def WhichOneof(self, oneof_group: typing_extensions.Literal["_setup_func", b"_setup_func"]) -> typing_extensions.Literal["setup_func"] | None: ...
|
|
41
43
|
|
|
42
44
|
global___FunctionCall = FunctionCall
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
@generated by mypy-protobuf. Do not edit manually!
|
|
3
3
|
isort:skip_file
|
|
4
4
|
"""
|
|
5
|
-
|
|
6
5
|
import builtins
|
|
7
6
|
import collections.abc
|
|
8
7
|
import google.protobuf.descriptor
|
|
@@ -62,7 +61,7 @@ STDOUT: LogLevel.ValueType # 5
|
|
|
62
61
|
STDERR: LogLevel.ValueType # 6
|
|
63
62
|
global___LogLevel = LogLevel
|
|
64
63
|
|
|
65
|
-
@
|
|
64
|
+
@typing_extensions.final
|
|
66
65
|
class SerializedObject(google.protobuf.message.Message):
|
|
67
66
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
68
67
|
|
|
@@ -90,13 +89,13 @@ class SerializedObject(google.protobuf.message.Message):
|
|
|
90
89
|
was_it_raised: builtins.bool = ...,
|
|
91
90
|
stringized_traceback: builtins.str | None = ...,
|
|
92
91
|
) -> None: ...
|
|
93
|
-
def HasField(self, field_name:
|
|
94
|
-
def ClearField(self, field_name:
|
|
95
|
-
def WhichOneof(self, oneof_group:
|
|
92
|
+
def HasField(self, field_name: typing_extensions.Literal["_stringized_traceback", b"_stringized_traceback", "stringized_traceback", b"stringized_traceback"]) -> builtins.bool: ...
|
|
93
|
+
def ClearField(self, field_name: typing_extensions.Literal["_stringized_traceback", b"_stringized_traceback", "definition", b"definition", "method", b"method", "stringized_traceback", b"stringized_traceback", "was_it_raised", b"was_it_raised"]) -> None: ...
|
|
94
|
+
def WhichOneof(self, oneof_group: typing_extensions.Literal["_stringized_traceback", b"_stringized_traceback"]) -> typing_extensions.Literal["stringized_traceback"] | None: ...
|
|
96
95
|
|
|
97
96
|
global___SerializedObject = SerializedObject
|
|
98
97
|
|
|
99
|
-
@
|
|
98
|
+
@typing_extensions.final
|
|
100
99
|
class PartialRunResult(google.protobuf.message.Message):
|
|
101
100
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
102
101
|
|
|
@@ -110,11 +109,9 @@ class PartialRunResult(google.protobuf.message.Message):
|
|
|
110
109
|
"""A list of logs collected during this partial execution. It does
|
|
111
110
|
not include old logs.
|
|
112
111
|
"""
|
|
113
|
-
|
|
114
112
|
@property
|
|
115
113
|
def result(self) -> global___SerializedObject:
|
|
116
114
|
"""The result of the run, if it is complete."""
|
|
117
|
-
|
|
118
115
|
def __init__(
|
|
119
116
|
self,
|
|
120
117
|
*,
|
|
@@ -122,13 +119,13 @@ class PartialRunResult(google.protobuf.message.Message):
|
|
|
122
119
|
logs: collections.abc.Iterable[global___Log] | None = ...,
|
|
123
120
|
result: global___SerializedObject | None = ...,
|
|
124
121
|
) -> None: ...
|
|
125
|
-
def HasField(self, field_name:
|
|
126
|
-
def ClearField(self, field_name:
|
|
127
|
-
def WhichOneof(self, oneof_group:
|
|
122
|
+
def HasField(self, field_name: typing_extensions.Literal["_result", b"_result", "result", b"result"]) -> builtins.bool: ...
|
|
123
|
+
def ClearField(self, field_name: typing_extensions.Literal["_result", b"_result", "is_complete", b"is_complete", "logs", b"logs", "result", b"result"]) -> None: ...
|
|
124
|
+
def WhichOneof(self, oneof_group: typing_extensions.Literal["_result", b"_result"]) -> typing_extensions.Literal["result"] | None: ...
|
|
128
125
|
|
|
129
126
|
global___PartialRunResult = PartialRunResult
|
|
130
127
|
|
|
131
|
-
@
|
|
128
|
+
@typing_extensions.final
|
|
132
129
|
class Log(google.protobuf.message.Message):
|
|
133
130
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
134
131
|
|
|
@@ -149,7 +146,7 @@ class Log(google.protobuf.message.Message):
|
|
|
149
146
|
level: global___LogLevel.ValueType = ...,
|
|
150
147
|
timestamp: google.protobuf.timestamp_pb2.Timestamp | None = ...,
|
|
151
148
|
) -> None: ...
|
|
152
|
-
def HasField(self, field_name:
|
|
153
|
-
def ClearField(self, field_name:
|
|
149
|
+
def HasField(self, field_name: typing_extensions.Literal["timestamp", b"timestamp"]) -> builtins.bool: ...
|
|
150
|
+
def ClearField(self, field_name: typing_extensions.Literal["level", b"level", "message", b"message", "source", b"source", "timestamp", b"timestamp"]) -> None: ...
|
|
154
151
|
|
|
155
152
|
global___Log = Log
|
isolate/logger.py
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
+
from typing import Dict
|
|
4
|
+
|
|
5
|
+
from isolate.logs import LogLevel, LogSource
|
|
3
6
|
|
|
4
7
|
|
|
5
8
|
# NOTE: we probably should've created a proper `logging.getLogger` here,
|
|
6
9
|
# but it handling `source` would be not trivial, so we are better off
|
|
7
10
|
# just keeping it simple for now.
|
|
8
11
|
class IsolateLogger:
|
|
9
|
-
def __init__(self):
|
|
10
|
-
self.log_labels =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
labels = json.loads(raw)
|
|
14
|
-
for key, value in labels.items():
|
|
15
|
-
if value.startswith("$"):
|
|
16
|
-
expanded = os.getenv(value[1:])
|
|
17
|
-
else:
|
|
18
|
-
expanded = value
|
|
19
|
-
self.log_labels[key] = expanded
|
|
20
|
-
|
|
21
|
-
def log(self, level, message, source):
|
|
12
|
+
def __init__(self, log_labels: Dict[str, str]):
|
|
13
|
+
self.log_labels = log_labels
|
|
14
|
+
|
|
15
|
+
def log(self, level: LogLevel, message: str, source: LogSource) -> None:
|
|
22
16
|
record = {
|
|
23
17
|
"isolate_source": source.name,
|
|
24
18
|
"level": level.name,
|
|
@@ -27,5 +21,29 @@ class IsolateLogger:
|
|
|
27
21
|
}
|
|
28
22
|
print(json.dumps(record))
|
|
29
23
|
|
|
24
|
+
@classmethod
|
|
25
|
+
def with_env_expanded(cls, labels: Dict[str, str]) -> "IsolateLogger":
|
|
26
|
+
for key, value in labels.items():
|
|
27
|
+
if value.startswith("$"):
|
|
28
|
+
expanded = os.getenv(value[1:])
|
|
29
|
+
else:
|
|
30
|
+
expanded = value
|
|
31
|
+
if expanded is not None:
|
|
32
|
+
labels[key] = expanded
|
|
33
|
+
|
|
34
|
+
return cls(labels)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_env(cls) -> "IsolateLogger":
|
|
38
|
+
_labels: Dict[str, str] = {}
|
|
39
|
+
raw = os.getenv("ISOLATE_LOG_LABELS")
|
|
40
|
+
if raw:
|
|
41
|
+
try:
|
|
42
|
+
_labels = json.loads(raw)
|
|
43
|
+
except json.JSONDecodeError:
|
|
44
|
+
print("Failed to parse ISOLATE_LOG_LABELS")
|
|
45
|
+
|
|
46
|
+
return cls.with_env_expanded(labels=_labels)
|
|
47
|
+
|
|
30
48
|
|
|
31
|
-
|
|
49
|
+
ENV_LOGGER = IsolateLogger.from_env()
|
|
@@ -11,6 +11,9 @@ service Isolate {
|
|
|
11
11
|
// Submit a function to be run without waiting for results.
|
|
12
12
|
rpc Submit (SubmitRequest) returns (SubmitResponse) {}
|
|
13
13
|
|
|
14
|
+
// Set the metadata for a task.
|
|
15
|
+
rpc SetMetadata (SetMetadataRequest) returns (SetMetadataResponse) {}
|
|
16
|
+
|
|
14
17
|
// List running tasks
|
|
15
18
|
rpc List (ListRequest) returns (ListResponse) {}
|
|
16
19
|
|
|
@@ -36,12 +39,27 @@ message EnvironmentDefinition {
|
|
|
36
39
|
message SubmitRequest {
|
|
37
40
|
// The function to run.
|
|
38
41
|
BoundFunction function = 1;
|
|
42
|
+
// Task metadata.
|
|
43
|
+
TaskMetadata metadata = 2;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
message TaskMetadata {
|
|
47
|
+
// Labels to attach to the logs.
|
|
48
|
+
map<string, string> logger_labels = 1;
|
|
39
49
|
}
|
|
40
50
|
|
|
41
51
|
message SubmitResponse {
|
|
42
52
|
string task_id = 1;
|
|
43
53
|
}
|
|
44
54
|
|
|
55
|
+
message SetMetadataRequest{
|
|
56
|
+
string task_id = 1;
|
|
57
|
+
TaskMetadata metadata = 2;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
message SetMetadataResponse {
|
|
61
|
+
}
|
|
62
|
+
|
|
45
63
|
message ListRequest {
|
|
46
64
|
}
|
|
47
65
|
|
|
@@ -16,31 +16,41 @@ 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\"
|
|
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\"R\n\rSubmitRequest\x12 \n\x08\x66unction\x18\x01 \x01(\x0b\x32\x0e.BoundFunction\x12\x1f\n\x08metadata\x18\x02 \x01(\x0b\x32\r.TaskMetadata\"{\n\x0cTaskMetadata\x12\x36\n\rlogger_labels\x18\x01 \x03(\x0b\x32\x1f.TaskMetadata.LoggerLabelsEntry\x1a\x33\n\x11LoggerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"!\n\x0eSubmitResponse\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"F\n\x12SetMetadataRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x1f\n\x08metadata\x18\x02 \x01(\x0b\x32\r.TaskMetadata\"\x15\n\x13SetMetadataResponse\"\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\xf4\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\x0bSetMetadata\x12\x13.SetMetadataRequest\x1a\x14.SetMetadataResponse\"\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)
|
|
23
23
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'server_pb2', _globals)
|
|
24
24
|
if not _descriptor._USE_C_DESCRIPTORS:
|
|
25
25
|
DESCRIPTOR._loaded_options = None
|
|
26
|
+
_globals['_TASKMETADATA_LOGGERLABELSENTRY']._loaded_options = None
|
|
27
|
+
_globals['_TASKMETADATA_LOGGERLABELSENTRY']._serialized_options = b'8\001'
|
|
26
28
|
_globals['_BOUNDFUNCTION']._serialized_start=61
|
|
27
29
|
_globals['_BOUNDFUNCTION']._serialized_end=218
|
|
28
30
|
_globals['_ENVIRONMENTDEFINITION']._serialized_start=220
|
|
29
31
|
_globals['_ENVIRONMENTDEFINITION']._serialized_end=320
|
|
30
32
|
_globals['_SUBMITREQUEST']._serialized_start=322
|
|
31
|
-
_globals['_SUBMITREQUEST']._serialized_end=
|
|
32
|
-
_globals['
|
|
33
|
-
_globals['
|
|
34
|
-
_globals['
|
|
35
|
-
_globals['
|
|
36
|
-
_globals['
|
|
37
|
-
_globals['
|
|
38
|
-
_globals['
|
|
39
|
-
_globals['
|
|
40
|
-
_globals['
|
|
41
|
-
_globals['
|
|
42
|
-
_globals['
|
|
43
|
-
_globals['
|
|
44
|
-
_globals['
|
|
45
|
-
_globals['
|
|
33
|
+
_globals['_SUBMITREQUEST']._serialized_end=404
|
|
34
|
+
_globals['_TASKMETADATA']._serialized_start=406
|
|
35
|
+
_globals['_TASKMETADATA']._serialized_end=529
|
|
36
|
+
_globals['_TASKMETADATA_LOGGERLABELSENTRY']._serialized_start=478
|
|
37
|
+
_globals['_TASKMETADATA_LOGGERLABELSENTRY']._serialized_end=529
|
|
38
|
+
_globals['_SUBMITRESPONSE']._serialized_start=531
|
|
39
|
+
_globals['_SUBMITRESPONSE']._serialized_end=564
|
|
40
|
+
_globals['_SETMETADATAREQUEST']._serialized_start=566
|
|
41
|
+
_globals['_SETMETADATAREQUEST']._serialized_end=636
|
|
42
|
+
_globals['_SETMETADATARESPONSE']._serialized_start=638
|
|
43
|
+
_globals['_SETMETADATARESPONSE']._serialized_end=659
|
|
44
|
+
_globals['_LISTREQUEST']._serialized_start=661
|
|
45
|
+
_globals['_LISTREQUEST']._serialized_end=674
|
|
46
|
+
_globals['_TASKINFO']._serialized_start=676
|
|
47
|
+
_globals['_TASKINFO']._serialized_end=703
|
|
48
|
+
_globals['_LISTRESPONSE']._serialized_start=705
|
|
49
|
+
_globals['_LISTRESPONSE']._serialized_end=745
|
|
50
|
+
_globals['_CANCELREQUEST']._serialized_start=747
|
|
51
|
+
_globals['_CANCELREQUEST']._serialized_end=779
|
|
52
|
+
_globals['_CANCELRESPONSE']._serialized_start=781
|
|
53
|
+
_globals['_CANCELRESPONSE']._serialized_end=797
|
|
54
|
+
_globals['_ISOLATE']._serialized_start=800
|
|
55
|
+
_globals['_ISOLATE']._serialized_end=1044
|
|
46
56
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
@generated by mypy-protobuf. Do not edit manually!
|
|
3
3
|
isort:skip_file
|
|
4
4
|
"""
|
|
5
|
-
|
|
6
5
|
import builtins
|
|
7
6
|
import collections.abc
|
|
8
7
|
from isolate.connections.grpc.definitions import common_pb2
|
|
@@ -10,11 +9,16 @@ import google.protobuf.descriptor
|
|
|
10
9
|
import google.protobuf.internal.containers
|
|
11
10
|
import google.protobuf.message
|
|
12
11
|
import google.protobuf.struct_pb2
|
|
13
|
-
import
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
if sys.version_info >= (3, 8):
|
|
15
|
+
import typing as typing_extensions
|
|
16
|
+
else:
|
|
17
|
+
import typing_extensions
|
|
14
18
|
|
|
15
19
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
|
16
20
|
|
|
17
|
-
@
|
|
21
|
+
@typing_extensions.final
|
|
18
22
|
class BoundFunction(google.protobuf.message.Message):
|
|
19
23
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
20
24
|
|
|
@@ -34,13 +38,13 @@ class BoundFunction(google.protobuf.message.Message):
|
|
|
34
38
|
function: common_pb2.SerializedObject | None = ...,
|
|
35
39
|
setup_func: common_pb2.SerializedObject | None = ...,
|
|
36
40
|
) -> None: ...
|
|
37
|
-
def HasField(self, field_name:
|
|
38
|
-
def ClearField(self, field_name:
|
|
39
|
-
def WhichOneof(self, oneof_group:
|
|
41
|
+
def HasField(self, field_name: typing_extensions.Literal["_setup_func", b"_setup_func", "function", b"function", "setup_func", b"setup_func"]) -> builtins.bool: ...
|
|
42
|
+
def ClearField(self, field_name: typing_extensions.Literal["_setup_func", b"_setup_func", "environments", b"environments", "function", b"function", "setup_func", b"setup_func"]) -> None: ...
|
|
43
|
+
def WhichOneof(self, oneof_group: typing_extensions.Literal["_setup_func", b"_setup_func"]) -> typing_extensions.Literal["setup_func"] | None: ...
|
|
40
44
|
|
|
41
45
|
global___BoundFunction = BoundFunction
|
|
42
46
|
|
|
43
|
-
@
|
|
47
|
+
@typing_extensions.final
|
|
44
48
|
class EnvironmentDefinition(google.protobuf.message.Message):
|
|
45
49
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
46
50
|
|
|
@@ -49,12 +53,11 @@ class EnvironmentDefinition(google.protobuf.message.Message):
|
|
|
49
53
|
FORCE_FIELD_NUMBER: builtins.int
|
|
50
54
|
kind: builtins.str
|
|
51
55
|
"""Kind of the isolate environment."""
|
|
52
|
-
force: builtins.bool
|
|
53
|
-
"""Whether to force-create this environment or not."""
|
|
54
56
|
@property
|
|
55
57
|
def configuration(self) -> google.protobuf.struct_pb2.Struct:
|
|
56
58
|
"""A free-form definition of environment properties."""
|
|
57
|
-
|
|
59
|
+
force: builtins.bool
|
|
60
|
+
"""Whether to force-create this environment or not."""
|
|
58
61
|
def __init__(
|
|
59
62
|
self,
|
|
60
63
|
*,
|
|
@@ -62,31 +65,68 @@ class EnvironmentDefinition(google.protobuf.message.Message):
|
|
|
62
65
|
configuration: google.protobuf.struct_pb2.Struct | None = ...,
|
|
63
66
|
force: builtins.bool = ...,
|
|
64
67
|
) -> None: ...
|
|
65
|
-
def HasField(self, field_name:
|
|
66
|
-
def ClearField(self, field_name:
|
|
68
|
+
def HasField(self, field_name: typing_extensions.Literal["configuration", b"configuration"]) -> builtins.bool: ...
|
|
69
|
+
def ClearField(self, field_name: typing_extensions.Literal["configuration", b"configuration", "force", b"force", "kind", b"kind"]) -> None: ...
|
|
67
70
|
|
|
68
71
|
global___EnvironmentDefinition = EnvironmentDefinition
|
|
69
72
|
|
|
70
|
-
@
|
|
73
|
+
@typing_extensions.final
|
|
71
74
|
class SubmitRequest(google.protobuf.message.Message):
|
|
72
75
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
73
76
|
|
|
74
77
|
FUNCTION_FIELD_NUMBER: builtins.int
|
|
78
|
+
METADATA_FIELD_NUMBER: builtins.int
|
|
75
79
|
@property
|
|
76
80
|
def function(self) -> global___BoundFunction:
|
|
77
81
|
"""The function to run."""
|
|
78
|
-
|
|
82
|
+
@property
|
|
83
|
+
def metadata(self) -> global___TaskMetadata:
|
|
84
|
+
"""Task metadata."""
|
|
79
85
|
def __init__(
|
|
80
86
|
self,
|
|
81
87
|
*,
|
|
82
88
|
function: global___BoundFunction | None = ...,
|
|
89
|
+
metadata: global___TaskMetadata | None = ...,
|
|
83
90
|
) -> None: ...
|
|
84
|
-
def HasField(self, field_name:
|
|
85
|
-
def ClearField(self, field_name:
|
|
91
|
+
def HasField(self, field_name: typing_extensions.Literal["function", b"function", "metadata", b"metadata"]) -> builtins.bool: ...
|
|
92
|
+
def ClearField(self, field_name: typing_extensions.Literal["function", b"function", "metadata", b"metadata"]) -> None: ...
|
|
86
93
|
|
|
87
94
|
global___SubmitRequest = SubmitRequest
|
|
88
95
|
|
|
89
|
-
@
|
|
96
|
+
@typing_extensions.final
|
|
97
|
+
class TaskMetadata(google.protobuf.message.Message):
|
|
98
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
99
|
+
|
|
100
|
+
@typing_extensions.final
|
|
101
|
+
class LoggerLabelsEntry(google.protobuf.message.Message):
|
|
102
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
103
|
+
|
|
104
|
+
KEY_FIELD_NUMBER: builtins.int
|
|
105
|
+
VALUE_FIELD_NUMBER: builtins.int
|
|
106
|
+
key: builtins.str
|
|
107
|
+
value: builtins.str
|
|
108
|
+
def __init__(
|
|
109
|
+
self,
|
|
110
|
+
*,
|
|
111
|
+
key: builtins.str = ...,
|
|
112
|
+
value: builtins.str = ...,
|
|
113
|
+
) -> None: ...
|
|
114
|
+
def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ...
|
|
115
|
+
|
|
116
|
+
LOGGER_LABELS_FIELD_NUMBER: builtins.int
|
|
117
|
+
@property
|
|
118
|
+
def logger_labels(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]:
|
|
119
|
+
"""Labels to attach to the logs."""
|
|
120
|
+
def __init__(
|
|
121
|
+
self,
|
|
122
|
+
*,
|
|
123
|
+
logger_labels: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
|
|
124
|
+
) -> None: ...
|
|
125
|
+
def ClearField(self, field_name: typing_extensions.Literal["logger_labels", b"logger_labels"]) -> None: ...
|
|
126
|
+
|
|
127
|
+
global___TaskMetadata = TaskMetadata
|
|
128
|
+
|
|
129
|
+
@typing_extensions.final
|
|
90
130
|
class SubmitResponse(google.protobuf.message.Message):
|
|
91
131
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
92
132
|
|
|
@@ -97,11 +137,41 @@ class SubmitResponse(google.protobuf.message.Message):
|
|
|
97
137
|
*,
|
|
98
138
|
task_id: builtins.str = ...,
|
|
99
139
|
) -> None: ...
|
|
100
|
-
def ClearField(self, field_name:
|
|
140
|
+
def ClearField(self, field_name: typing_extensions.Literal["task_id", b"task_id"]) -> None: ...
|
|
101
141
|
|
|
102
142
|
global___SubmitResponse = SubmitResponse
|
|
103
143
|
|
|
104
|
-
@
|
|
144
|
+
@typing_extensions.final
|
|
145
|
+
class SetMetadataRequest(google.protobuf.message.Message):
|
|
146
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
147
|
+
|
|
148
|
+
TASK_ID_FIELD_NUMBER: builtins.int
|
|
149
|
+
METADATA_FIELD_NUMBER: builtins.int
|
|
150
|
+
task_id: builtins.str
|
|
151
|
+
@property
|
|
152
|
+
def metadata(self) -> global___TaskMetadata: ...
|
|
153
|
+
def __init__(
|
|
154
|
+
self,
|
|
155
|
+
*,
|
|
156
|
+
task_id: builtins.str = ...,
|
|
157
|
+
metadata: global___TaskMetadata | None = ...,
|
|
158
|
+
) -> None: ...
|
|
159
|
+
def HasField(self, field_name: typing_extensions.Literal["metadata", b"metadata"]) -> builtins.bool: ...
|
|
160
|
+
def ClearField(self, field_name: typing_extensions.Literal["metadata", b"metadata", "task_id", b"task_id"]) -> None: ...
|
|
161
|
+
|
|
162
|
+
global___SetMetadataRequest = SetMetadataRequest
|
|
163
|
+
|
|
164
|
+
@typing_extensions.final
|
|
165
|
+
class SetMetadataResponse(google.protobuf.message.Message):
|
|
166
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
167
|
+
|
|
168
|
+
def __init__(
|
|
169
|
+
self,
|
|
170
|
+
) -> None: ...
|
|
171
|
+
|
|
172
|
+
global___SetMetadataResponse = SetMetadataResponse
|
|
173
|
+
|
|
174
|
+
@typing_extensions.final
|
|
105
175
|
class ListRequest(google.protobuf.message.Message):
|
|
106
176
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
107
177
|
|
|
@@ -111,7 +181,7 @@ class ListRequest(google.protobuf.message.Message):
|
|
|
111
181
|
|
|
112
182
|
global___ListRequest = ListRequest
|
|
113
183
|
|
|
114
|
-
@
|
|
184
|
+
@typing_extensions.final
|
|
115
185
|
class TaskInfo(google.protobuf.message.Message):
|
|
116
186
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
117
187
|
|
|
@@ -122,11 +192,11 @@ class TaskInfo(google.protobuf.message.Message):
|
|
|
122
192
|
*,
|
|
123
193
|
task_id: builtins.str = ...,
|
|
124
194
|
) -> None: ...
|
|
125
|
-
def ClearField(self, field_name:
|
|
195
|
+
def ClearField(self, field_name: typing_extensions.Literal["task_id", b"task_id"]) -> None: ...
|
|
126
196
|
|
|
127
197
|
global___TaskInfo = TaskInfo
|
|
128
198
|
|
|
129
|
-
@
|
|
199
|
+
@typing_extensions.final
|
|
130
200
|
class ListResponse(google.protobuf.message.Message):
|
|
131
201
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
132
202
|
|
|
@@ -138,11 +208,11 @@ class ListResponse(google.protobuf.message.Message):
|
|
|
138
208
|
*,
|
|
139
209
|
tasks: collections.abc.Iterable[global___TaskInfo] | None = ...,
|
|
140
210
|
) -> None: ...
|
|
141
|
-
def ClearField(self, field_name:
|
|
211
|
+
def ClearField(self, field_name: typing_extensions.Literal["tasks", b"tasks"]) -> None: ...
|
|
142
212
|
|
|
143
213
|
global___ListResponse = ListResponse
|
|
144
214
|
|
|
145
|
-
@
|
|
215
|
+
@typing_extensions.final
|
|
146
216
|
class CancelRequest(google.protobuf.message.Message):
|
|
147
217
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
148
218
|
|
|
@@ -153,11 +223,11 @@ class CancelRequest(google.protobuf.message.Message):
|
|
|
153
223
|
*,
|
|
154
224
|
task_id: builtins.str = ...,
|
|
155
225
|
) -> None: ...
|
|
156
|
-
def ClearField(self, field_name:
|
|
226
|
+
def ClearField(self, field_name: typing_extensions.Literal["task_id", b"task_id"]) -> None: ...
|
|
157
227
|
|
|
158
228
|
global___CancelRequest = CancelRequest
|
|
159
229
|
|
|
160
|
-
@
|
|
230
|
+
@typing_extensions.final
|
|
161
231
|
class CancelResponse(google.protobuf.message.Message):
|
|
162
232
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
163
233
|
|
|
@@ -50,6 +50,11 @@ 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.SetMetadata = channel.unary_unary(
|
|
54
|
+
'/Isolate/SetMetadata',
|
|
55
|
+
request_serializer=server__pb2.SetMetadataRequest.SerializeToString,
|
|
56
|
+
response_deserializer=server__pb2.SetMetadataResponse.FromString,
|
|
57
|
+
_registered_method=True)
|
|
53
58
|
self.List = channel.unary_unary(
|
|
54
59
|
'/Isolate/List',
|
|
55
60
|
request_serializer=server__pb2.ListRequest.SerializeToString,
|
|
@@ -80,6 +85,13 @@ class IsolateServicer(object):
|
|
|
80
85
|
context.set_details('Method not implemented!')
|
|
81
86
|
raise NotImplementedError('Method not implemented!')
|
|
82
87
|
|
|
88
|
+
def SetMetadata(self, request, context):
|
|
89
|
+
"""Set the metadata for a task.
|
|
90
|
+
"""
|
|
91
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
92
|
+
context.set_details('Method not implemented!')
|
|
93
|
+
raise NotImplementedError('Method not implemented!')
|
|
94
|
+
|
|
83
95
|
def List(self, request, context):
|
|
84
96
|
"""List running tasks
|
|
85
97
|
"""
|
|
@@ -107,6 +119,11 @@ def add_IsolateServicer_to_server(servicer, server):
|
|
|
107
119
|
request_deserializer=server__pb2.SubmitRequest.FromString,
|
|
108
120
|
response_serializer=server__pb2.SubmitResponse.SerializeToString,
|
|
109
121
|
),
|
|
122
|
+
'SetMetadata': grpc.unary_unary_rpc_method_handler(
|
|
123
|
+
servicer.SetMetadata,
|
|
124
|
+
request_deserializer=server__pb2.SetMetadataRequest.FromString,
|
|
125
|
+
response_serializer=server__pb2.SetMetadataResponse.SerializeToString,
|
|
126
|
+
),
|
|
110
127
|
'List': grpc.unary_unary_rpc_method_handler(
|
|
111
128
|
servicer.List,
|
|
112
129
|
request_deserializer=server__pb2.ListRequest.FromString,
|
|
@@ -182,6 +199,33 @@ class Isolate(object):
|
|
|
182
199
|
metadata,
|
|
183
200
|
_registered_method=True)
|
|
184
201
|
|
|
202
|
+
@staticmethod
|
|
203
|
+
def SetMetadata(request,
|
|
204
|
+
target,
|
|
205
|
+
options=(),
|
|
206
|
+
channel_credentials=None,
|
|
207
|
+
call_credentials=None,
|
|
208
|
+
insecure=False,
|
|
209
|
+
compression=None,
|
|
210
|
+
wait_for_ready=None,
|
|
211
|
+
timeout=None,
|
|
212
|
+
metadata=None):
|
|
213
|
+
return grpc.experimental.unary_unary(
|
|
214
|
+
request,
|
|
215
|
+
target,
|
|
216
|
+
'/Isolate/SetMetadata',
|
|
217
|
+
server__pb2.SetMetadataRequest.SerializeToString,
|
|
218
|
+
server__pb2.SetMetadataResponse.FromString,
|
|
219
|
+
options,
|
|
220
|
+
channel_credentials,
|
|
221
|
+
insecure,
|
|
222
|
+
call_credentials,
|
|
223
|
+
compression,
|
|
224
|
+
wait_for_ready,
|
|
225
|
+
timeout,
|
|
226
|
+
metadata,
|
|
227
|
+
_registered_method=True)
|
|
228
|
+
|
|
185
229
|
@staticmethod
|
|
186
230
|
def List(request,
|
|
187
231
|
target,
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
@generated by mypy-protobuf. Do not edit manually!
|
|
3
3
|
isort:skip_file
|
|
4
4
|
"""
|
|
5
|
-
|
|
6
5
|
import builtins
|
|
7
6
|
import google.protobuf.descriptor
|
|
8
7
|
import google.protobuf.internal.enum_type_wrapper
|
|
@@ -17,7 +16,7 @@ else:
|
|
|
17
16
|
|
|
18
17
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
|
19
18
|
|
|
20
|
-
@
|
|
19
|
+
@typing_extensions.final
|
|
21
20
|
class HealthCheckRequest(google.protobuf.message.Message):
|
|
22
21
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
23
22
|
|
|
@@ -28,11 +27,11 @@ class HealthCheckRequest(google.protobuf.message.Message):
|
|
|
28
27
|
*,
|
|
29
28
|
service: builtins.str = ...,
|
|
30
29
|
) -> None: ...
|
|
31
|
-
def ClearField(self, field_name:
|
|
30
|
+
def ClearField(self, field_name: typing_extensions.Literal["service", b"service"]) -> None: ...
|
|
32
31
|
|
|
33
32
|
global___HealthCheckRequest = HealthCheckRequest
|
|
34
33
|
|
|
35
|
-
@
|
|
34
|
+
@typing_extensions.final
|
|
36
35
|
class HealthCheckResponse(google.protobuf.message.Message):
|
|
37
36
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
38
37
|
|
|
@@ -62,6 +61,6 @@ class HealthCheckResponse(google.protobuf.message.Message):
|
|
|
62
61
|
*,
|
|
63
62
|
status: global___HealthCheckResponse.ServingStatus.ValueType = ...,
|
|
64
63
|
) -> None: ...
|
|
65
|
-
def ClearField(self, field_name:
|
|
64
|
+
def ClearField(self, field_name: typing_extensions.Literal["status", b"status"]) -> None: ...
|
|
66
65
|
|
|
67
66
|
global___HealthCheckResponse = HealthCheckResponse
|
isolate/server/server.py
CHANGED
|
@@ -29,13 +29,14 @@ from isolate.backends.local import LocalPythonEnvironment
|
|
|
29
29
|
from isolate.backends.virtualenv import VirtualPythonEnvironment
|
|
30
30
|
from isolate.connections.grpc import AgentError, LocalPythonGRPC
|
|
31
31
|
from isolate.connections.grpc.configuration import get_default_options
|
|
32
|
-
from isolate.logger import
|
|
32
|
+
from isolate.logger import ENV_LOGGER, IsolateLogger
|
|
33
33
|
from isolate.logs import Log, LogLevel, LogSource
|
|
34
34
|
from isolate.server import definitions, health
|
|
35
35
|
from isolate.server.health_server import HealthServicer
|
|
36
36
|
from isolate.server.interface import from_grpc, to_grpc
|
|
37
37
|
|
|
38
38
|
EMPTY_MESSAGE_INTERVAL = float(os.getenv("ISOLATE_EMPTY_MESSAGE_INTERVAL", "600"))
|
|
39
|
+
SKIP_EMPTY_LOGS = os.getenv("ISOLATE_SKIP_EMPTY_LOGS") == "1"
|
|
39
40
|
MAX_GRPC_WAIT_TIMEOUT = float(os.getenv("ISOLATE_MAX_GRPC_WAIT_TIMEOUT", "10.0"))
|
|
40
41
|
|
|
41
42
|
# Whether to inherit all the packages from the current environment or not.
|
|
@@ -174,6 +175,7 @@ class RunTask:
|
|
|
174
175
|
request: definitions.BoundFunction
|
|
175
176
|
future: futures.Future | None = None
|
|
176
177
|
agent: RunnerAgent | None = None
|
|
178
|
+
logger: IsolateLogger = ENV_LOGGER
|
|
177
179
|
|
|
178
180
|
def cancel(self):
|
|
179
181
|
while True:
|
|
@@ -210,7 +212,8 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
210
212
|
StatusCode.INVALID_ARGUMENT,
|
|
211
213
|
)
|
|
212
214
|
|
|
213
|
-
log_handler = LogHandler(messages)
|
|
215
|
+
log_handler = LogHandler(messages, task=task)
|
|
216
|
+
|
|
214
217
|
run_settings = replace(
|
|
215
218
|
self.default_settings,
|
|
216
219
|
log_hook=log_handler.handle,
|
|
@@ -321,11 +324,17 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
321
324
|
request: definitions.SubmitRequest,
|
|
322
325
|
context: ServicerContext,
|
|
323
326
|
) -> definitions.SubmitResponse:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
logger = ENV_LOGGER
|
|
328
|
+
if request.metadata.logger_labels:
|
|
329
|
+
logger_labels_dict = dict(request.metadata.logger_labels)
|
|
330
|
+
try:
|
|
331
|
+
logger = IsolateLogger.with_env_expanded(logger_labels_dict)
|
|
332
|
+
except BaseException:
|
|
333
|
+
# Ignore the error if the logger couldn't be created.
|
|
334
|
+
pass
|
|
335
|
+
|
|
336
|
+
task = RunTask(request=request.function, logger=logger)
|
|
337
|
+
task.future = RUNNER_THREAD_POOL.submit(self._run_task_in_background, task)
|
|
329
338
|
task_id = str(uuid.uuid4())
|
|
330
339
|
|
|
331
340
|
print(f"Submitted a task {task_id}")
|
|
@@ -345,6 +354,25 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
345
354
|
|
|
346
355
|
return definitions.SubmitResponse(task_id=task_id)
|
|
347
356
|
|
|
357
|
+
def SetMetadata(
|
|
358
|
+
self,
|
|
359
|
+
request: definitions.SetMetadataRequest,
|
|
360
|
+
context: ServicerContext,
|
|
361
|
+
) -> definitions.SetMetadataResponse:
|
|
362
|
+
if request.task_id not in self.background_tasks:
|
|
363
|
+
raise GRPCException(
|
|
364
|
+
f"Task {request.task_id} not found.",
|
|
365
|
+
StatusCode.NOT_FOUND,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
task = self.background_tasks[request.task_id]
|
|
369
|
+
|
|
370
|
+
task.logger = IsolateLogger.with_env_expanded(
|
|
371
|
+
dict(request.metadata.logger_labels)
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
return definitions.SetMetadataResponse()
|
|
375
|
+
|
|
348
376
|
def Run(
|
|
349
377
|
self,
|
|
350
378
|
request: definitions.BoundFunction,
|
|
@@ -437,7 +465,8 @@ class IsolateServicer(definitions.IsolateServicer):
|
|
|
437
465
|
return None
|
|
438
466
|
|
|
439
467
|
def cancel_tasks(self):
|
|
440
|
-
|
|
468
|
+
tasks_copy = self.background_tasks.copy()
|
|
469
|
+
for task in tasks_copy.values():
|
|
441
470
|
task.cancel()
|
|
442
471
|
|
|
443
472
|
|
|
@@ -453,10 +482,13 @@ def _proxy_to_queue(
|
|
|
453
482
|
@dataclass
|
|
454
483
|
class LogHandler:
|
|
455
484
|
messages: Queue
|
|
485
|
+
# Reference to the task so we can change the logger
|
|
486
|
+
task: RunTask
|
|
456
487
|
|
|
457
488
|
def handle(self, log: Log) -> None:
|
|
458
|
-
|
|
459
|
-
|
|
489
|
+
if not SKIP_EMPTY_LOGS or log.message.strip():
|
|
490
|
+
self.task.logger.log(log.level, log.message, source=log.source)
|
|
491
|
+
self._add_log_to_queue(log)
|
|
460
492
|
|
|
461
493
|
def _add_log_to_queue(self, log: Log) -> None:
|
|
462
494
|
grpc_log = cast(definitions.Log, to_grpc(log))
|
|
@@ -505,6 +537,16 @@ class SingleTaskInterceptor(ServerBoundInterceptor):
|
|
|
505
537
|
"""Sets server to terminate after the first Submit/Run task."""
|
|
506
538
|
|
|
507
539
|
_done: bool = False
|
|
540
|
+
_task_id: str | None = None
|
|
541
|
+
|
|
542
|
+
def __init__(self):
|
|
543
|
+
def terminate(request: Any, context: grpc.ServicerContext) -> Any:
|
|
544
|
+
context.abort(
|
|
545
|
+
grpc.StatusCode.RESOURCE_EXHAUSTED,
|
|
546
|
+
"Server has already served one Run/Submit task.",
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
self._terminator = grpc.unary_unary_rpc_method_handler(terminate)
|
|
508
550
|
|
|
509
551
|
def intercept_service(self, continuation, handler_call_details):
|
|
510
552
|
handler = continuation(handler_call_details)
|
|
@@ -513,29 +555,62 @@ class SingleTaskInterceptor(ServerBoundInterceptor):
|
|
|
513
555
|
is_run = handler_call_details.method == "/Isolate/Run"
|
|
514
556
|
is_new_task = is_submit or is_run
|
|
515
557
|
|
|
516
|
-
if is_new_task
|
|
517
|
-
raise grpc.RpcError(
|
|
518
|
-
grpc.StatusCode.UNAVAILABLE,
|
|
519
|
-
"Server has already served one Run/Submit task.",
|
|
520
|
-
)
|
|
521
|
-
elif is_new_task:
|
|
522
|
-
self._done = True
|
|
523
|
-
else:
|
|
558
|
+
if not is_new_task:
|
|
524
559
|
# Let other requests like List/Cancel/etc pass through
|
|
525
|
-
return
|
|
560
|
+
return handler
|
|
561
|
+
|
|
562
|
+
if self._done:
|
|
563
|
+
# Fail the request if the server has already served or is serving
|
|
564
|
+
# a Run/Submit task.
|
|
565
|
+
return self._terminator
|
|
566
|
+
|
|
567
|
+
self._done = True
|
|
526
568
|
|
|
527
569
|
def wrapper(method_impl):
|
|
528
570
|
@functools.wraps(method_impl)
|
|
529
|
-
def _wrapper(request, context):
|
|
530
|
-
def
|
|
531
|
-
if
|
|
532
|
-
|
|
533
|
-
|
|
571
|
+
def _wrapper(request: Any, context: grpc.ServicerContext) -> Any:
|
|
572
|
+
def termination() -> None:
|
|
573
|
+
if is_run:
|
|
574
|
+
print("Stopping server since run is finished")
|
|
575
|
+
# Stop the server after the Run task is finished
|
|
576
|
+
self.server.stop(grace=0.1)
|
|
577
|
+
|
|
578
|
+
elif is_submit:
|
|
579
|
+
# Wait until the task_id is assigned
|
|
580
|
+
while self._task_id is None:
|
|
534
581
|
time.sleep(0.1)
|
|
535
|
-
self.server.stop(grace=0.1)
|
|
536
582
|
|
|
537
|
-
|
|
538
|
-
|
|
583
|
+
# Get the task from the background tasks
|
|
584
|
+
task = self.servicer.background_tasks.get(self._task_id)
|
|
585
|
+
|
|
586
|
+
if task is not None:
|
|
587
|
+
# Wait until the task future is assigned
|
|
588
|
+
tries = 0
|
|
589
|
+
while task.future is None:
|
|
590
|
+
time.sleep(0.1)
|
|
591
|
+
tries += 1
|
|
592
|
+
if tries > 100:
|
|
593
|
+
raise RuntimeError(
|
|
594
|
+
"Task future was not assigned in time."
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
def _stop(*args):
|
|
598
|
+
# Small sleep to make sure the cancellation is processed
|
|
599
|
+
time.sleep(0.1)
|
|
600
|
+
print("Stopping server since the task is finished")
|
|
601
|
+
self.server.stop(grace=0.1)
|
|
602
|
+
|
|
603
|
+
# Add a callback which will stop the server
|
|
604
|
+
# after the task is finished
|
|
605
|
+
task.future.add_done_callback(_stop)
|
|
606
|
+
|
|
607
|
+
context.add_callback(termination)
|
|
608
|
+
res = method_impl(request, context)
|
|
609
|
+
|
|
610
|
+
if is_submit:
|
|
611
|
+
self._task_id = cast(definitions.SubmitResponse, res).task_id
|
|
612
|
+
|
|
613
|
+
return res
|
|
539
614
|
|
|
540
615
|
return _wrapper
|
|
541
616
|
|
|
@@ -569,7 +644,7 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
569
644
|
server = grpc.server(
|
|
570
645
|
futures.ThreadPoolExecutor(max_workers=options.num_workers),
|
|
571
646
|
options=get_default_options(),
|
|
572
|
-
interceptors=interceptors,
|
|
647
|
+
interceptors=interceptors, # type: ignore
|
|
573
648
|
)
|
|
574
649
|
|
|
575
650
|
for interceptor in interceptors:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
isolate/__init__.py,sha256=uXOKnONs7sXgARNgElwr4_A1sKoA6ACHVEvs3IDiX1M,127
|
|
2
|
-
isolate/_isolate_version.py,sha256=
|
|
2
|
+
isolate/_isolate_version.py,sha256=2Ctgubb5b_lxFG2ixV07ZYKw5eto45wRlKsBIObkGsg,413
|
|
3
3
|
isolate/_version.py,sha256=05pXvy-yr5t3I1m9JMn42Ilzpg7fa8IB2J8a3G7t1cU,274
|
|
4
|
-
isolate/logger.py,sha256=
|
|
4
|
+
isolate/logger.py,sha256=d9mZyTOtplMZeQSNgRNiXhOPwJ0be2B1nGGaQx09C3g,1450
|
|
5
5
|
isolate/logs.py,sha256=R_AHUVYD18z_PhtK_mDWi9Gch79CxmwHY09hUDShtwg,2079
|
|
6
6
|
isolate/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
isolate/registry.py,sha256=hpzv4HI7iihG5I7i5r8Pb257ibhEKY18xQcG-w1-BgI,1590
|
|
@@ -30,11 +30,11 @@ isolate/connections/grpc/interface.py,sha256=yt63kytgXRXrTnjePGJVdXz4LJJVSSrNkJC
|
|
|
30
30
|
isolate/connections/grpc/definitions/__init__.py,sha256=Z0453Bbjoq-Oxm2Wfi9fae-BFf8YsZwmuh88strmvxo,459
|
|
31
31
|
isolate/connections/grpc/definitions/agent.proto,sha256=Hx11hHc8PKwhWzyasViLeq7JL33KsRex2-iibfWruTw,568
|
|
32
32
|
isolate/connections/grpc/definitions/agent_pb2.py,sha256=F8KVIE1CK542c7_EJKJ40LY8mPZwEqvdmgBPntAMqE0,1424
|
|
33
|
-
isolate/connections/grpc/definitions/agent_pb2.pyi,sha256=
|
|
33
|
+
isolate/connections/grpc/definitions/agent_pb2.pyi,sha256=IKJHEq01DZRIy4xrtpHalJmM56IQCZRxFEOZEs7hCUw,1744
|
|
34
34
|
isolate/connections/grpc/definitions/agent_pb2_grpc.py,sha256=7tm-RB4CTu_YmqvI7QGRll1Z1NmkMWY2Vm-4AHr57X8,3632
|
|
35
35
|
isolate/connections/grpc/definitions/common.proto,sha256=4W1upvDIPezNj-Ab6FVNa-7cA9_N-2xJMJpwytRhpCw,1260
|
|
36
36
|
isolate/connections/grpc/definitions/common_pb2.py,sha256=lkpvpARZbPDrzrVkKJ-4WZWISN2kzrzJPNBUczmvkHU,2464
|
|
37
|
-
isolate/connections/grpc/definitions/common_pb2.pyi,sha256=
|
|
37
|
+
isolate/connections/grpc/definitions/common_pb2.pyi,sha256=J3av86ZHoHR28_5zshqCJ0I7v9WCxuQsvOAin-zig9w,6222
|
|
38
38
|
isolate/connections/grpc/definitions/common_pb2_grpc.py,sha256=EvGJ0LYaWTflBesxg0P1nh_EeWKYKqUVRf0_plMISTs,1123
|
|
39
39
|
isolate/connections/ipc/__init__.py,sha256=j2Mbsph2mRhAWmkMyrtPOz0VG-e75h1OOZLwzs6pXUo,131
|
|
40
40
|
isolate/connections/ipc/_base.py,sha256=Jk715XK2ei3yBpFcwUnFZ0owQMMf5jekZFNh2WlKRT4,8009
|
|
@@ -42,20 +42,20 @@ isolate/connections/ipc/agent.py,sha256=hGlL4x78FhRvMZ4DkVh3dk-EmWQqxHW4LIipgyOk
|
|
|
42
42
|
isolate/server/__init__.py,sha256=7R3GuWmxuqe0q28rVqETJN9OCrP_-Svjv9h0NR1GFL0,79
|
|
43
43
|
isolate/server/health_server.py,sha256=yN7F1Q28DdX8-Zk3gef7XcQEE25XwlHwzV5GBM75aQM,1249
|
|
44
44
|
isolate/server/interface.py,sha256=nGbjdxrN0p9m1LNdeds8NIoJOwPYW2NM6ktmbhfG4_s,687
|
|
45
|
-
isolate/server/server.py,sha256=
|
|
45
|
+
isolate/server/server.py,sha256=q0g0dL8hOosogGWpZMpXOOohTV55itp6f4K5yenvtBg,23233
|
|
46
46
|
isolate/server/definitions/__init__.py,sha256=f_Q3pdjMuZrjgNlbM60btFKiB1Vg8cnVyKEbp0RmU0A,572
|
|
47
|
-
isolate/server/definitions/server.proto,sha256=
|
|
48
|
-
isolate/server/definitions/server_pb2.py,sha256=
|
|
49
|
-
isolate/server/definitions/server_pb2.pyi,sha256=
|
|
50
|
-
isolate/server/definitions/server_pb2_grpc.py,sha256=
|
|
47
|
+
isolate/server/definitions/server.proto,sha256=UihlFbYG8fbwm0IUfKDRH1vNkopzP3C-wplXXcAO1c8,1761
|
|
48
|
+
isolate/server/definitions/server_pb2.py,sha256=TYBJC_z_dNf2J6FgHukY9mDyc3WBt9EPQOVFd_ayQNc,4304
|
|
49
|
+
isolate/server/definitions/server_pb2.pyi,sha256=bGDzwxvYJEq_N7R4mvE86t_GhBfUx8eXRYbrvOzFhqc,8352
|
|
50
|
+
isolate/server/definitions/server_pb2_grpc.py,sha256=TUKXKlT-6oOpZ2zg8EhJ-XFvjKGX90ze4iY0f5R6ZHU,10107
|
|
51
51
|
isolate/server/health/__init__.py,sha256=sy349GRK2YGX9KFKqDxM-jdYtBpMXjZu1QwBkjn0SsM,337
|
|
52
52
|
isolate/server/health/health.proto,sha256=wE2_QD0OQAblKkEBG7sALLXEOj1mOLKG-FbC4tFopWE,455
|
|
53
53
|
isolate/server/health/health_pb2.py,sha256=onOdP3M4Tpqhqs2PlGcyfoKe2VVKUEDx5ALeRcObb9A,1899
|
|
54
|
-
isolate/server/health/health_pb2.pyi,sha256=
|
|
54
|
+
isolate/server/health/health_pb2.pyi,sha256=AK-DPCpJzoYhU6DydD856c0Ywx84x6k-Cs4m6HpNv5A,2459
|
|
55
55
|
isolate/server/health/health_pb2_grpc.py,sha256=XgsULrnRBmYIqvKr8eI7bqs6NIea5A0kkqdOOc2JHBY,5303
|
|
56
|
-
isolate-0.
|
|
57
|
-
isolate-0.
|
|
58
|
-
isolate-0.
|
|
59
|
-
isolate-0.
|
|
60
|
-
isolate-0.
|
|
61
|
-
isolate-0.
|
|
56
|
+
isolate-0.14.1.dist-info/LICENSE,sha256=427vuyirL5scgBLqA9UWcdnxKrtSGc0u_JfUupk6lAA,11359
|
|
57
|
+
isolate-0.14.1.dist-info/METADATA,sha256=_B69rNK-IJtBqsUjNwPXijhI_uLVcBTSLJ3jcbfl8Dk,3191
|
|
58
|
+
isolate-0.14.1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
59
|
+
isolate-0.14.1.dist-info/entry_points.txt,sha256=s3prh2EERaVCbL8R45tfY5WFPZ1TsYOsz305YR7s-Pc,360
|
|
60
|
+
isolate-0.14.1.dist-info/top_level.txt,sha256=W9QJBHcq5WXRkbOXf25bvftzFsOZZN4n1DAatdroZrs,8
|
|
61
|
+
isolate-0.14.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|