digitalkin 0.2.12__py3-none-any.whl → 0.2.14__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.
- digitalkin/__version__.py +1 -1
- digitalkin/grpc_servers/_base_server.py +15 -17
- digitalkin/grpc_servers/module_server.py +9 -10
- digitalkin/grpc_servers/module_servicer.py +199 -85
- digitalkin/grpc_servers/registry_server.py +3 -6
- digitalkin/grpc_servers/registry_servicer.py +18 -19
- digitalkin/grpc_servers/utils/exceptions.py +4 -0
- digitalkin/grpc_servers/utils/grpc_client_wrapper.py +3 -5
- digitalkin/logger.py +45 -1
- digitalkin/models/module/__init__.py +2 -1
- digitalkin/models/module/module.py +1 -0
- digitalkin/models/module/module_types.py +1 -0
- digitalkin/modules/_base_module.py +124 -7
- digitalkin/modules/archetype_module.py +11 -1
- digitalkin/modules/job_manager/base_job_manager.py +181 -0
- digitalkin/modules/job_manager/job_manager_models.py +44 -0
- digitalkin/modules/job_manager/single_job_manager.py +285 -0
- digitalkin/modules/job_manager/taskiq_broker.py +214 -0
- digitalkin/modules/job_manager/taskiq_job_manager.py +286 -0
- digitalkin/modules/tool_module.py +2 -1
- digitalkin/modules/trigger_module.py +3 -1
- digitalkin/services/cost/default_cost.py +8 -4
- digitalkin/services/cost/grpc_cost.py +15 -7
- digitalkin/services/filesystem/default_filesystem.py +2 -4
- digitalkin/services/filesystem/grpc_filesystem.py +8 -5
- digitalkin/services/setup/__init__.py +1 -0
- digitalkin/services/setup/default_setup.py +10 -12
- digitalkin/services/setup/grpc_setup.py +8 -10
- digitalkin/services/storage/default_storage.py +11 -5
- digitalkin/services/storage/grpc_storage.py +23 -8
- digitalkin/utils/arg_parser.py +5 -48
- digitalkin/utils/development_mode_action.py +51 -0
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.14.dist-info}/METADATA +46 -15
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.14.dist-info}/RECORD +41 -34
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.14.dist-info}/WHEEL +1 -1
- modules/cpu_intensive_module.py +281 -0
- modules/minimal_llm_module.py +240 -58
- modules/storage_module.py +5 -6
- modules/text_transform_module.py +1 -1
- digitalkin/modules/job_manager.py +0 -177
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.14.dist-info}/licenses/LICENSE +0 -0
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.14.dist-info}/top_level.txt +0 -0
digitalkin/__version__.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
4
|
import asyncio
|
|
5
|
-
import logging
|
|
6
5
|
from collections.abc import Callable
|
|
7
6
|
from concurrent import futures
|
|
8
7
|
from pathlib import Path
|
|
@@ -20,8 +19,7 @@ from digitalkin.grpc_servers.utils.exceptions import (
|
|
|
20
19
|
)
|
|
21
20
|
from digitalkin.grpc_servers.utils.models import SecurityMode, ServerConfig, ServerMode
|
|
22
21
|
from digitalkin.grpc_servers.utils.types import GrpcServer, ServiceDescriptor, T
|
|
23
|
-
|
|
24
|
-
logger = logging.getLogger(__name__)
|
|
22
|
+
from digitalkin.logger import logger
|
|
25
23
|
|
|
26
24
|
|
|
27
25
|
class BaseServer(abc.ABC):
|
|
@@ -132,7 +130,7 @@ class BaseServer(abc.ABC):
|
|
|
132
130
|
# reflection queries with detailed service information
|
|
133
131
|
reflection.enable_server_reflection(service_names, self.server)
|
|
134
132
|
|
|
135
|
-
logger.
|
|
133
|
+
logger.debug("Added gRPC reflection service with services: %s", service_names)
|
|
136
134
|
except ImportError:
|
|
137
135
|
logger.warning("Could not enable reflection: grpcio-reflection package not installed")
|
|
138
136
|
except Exception as e:
|
|
@@ -165,7 +163,7 @@ class BaseServer(abc.ABC):
|
|
|
165
163
|
if service_name not in self._service_names:
|
|
166
164
|
self._service_names.append(service_name)
|
|
167
165
|
|
|
168
|
-
logger.
|
|
166
|
+
logger.debug("Added gRPC health checking service")
|
|
169
167
|
|
|
170
168
|
# Set all services as SERVING
|
|
171
169
|
for service_name in self._service_names:
|
|
@@ -255,7 +253,7 @@ class BaseServer(abc.ABC):
|
|
|
255
253
|
sync_server = cast("grpc.Server", server)
|
|
256
254
|
sync_server.add_secure_port(self.config.address, server_credentials)
|
|
257
255
|
|
|
258
|
-
logger.
|
|
256
|
+
logger.debug("Added secure port %s", self.config.address)
|
|
259
257
|
except Exception as e:
|
|
260
258
|
msg = f"Failed to configure secure port: {e}"
|
|
261
259
|
raise SecurityError(msg) from e
|
|
@@ -277,7 +275,7 @@ class BaseServer(abc.ABC):
|
|
|
277
275
|
sync_server = cast("grpc.Server", server)
|
|
278
276
|
sync_server.add_insecure_port(self.config.address)
|
|
279
277
|
|
|
280
|
-
logger.
|
|
278
|
+
logger.debug("Added insecure port %s", self.config.address)
|
|
281
279
|
except Exception as e:
|
|
282
280
|
msg = f"Failed to add insecure port: {e}"
|
|
283
281
|
raise ConfigurationError(msg) from e
|
|
@@ -301,7 +299,7 @@ class BaseServer(abc.ABC):
|
|
|
301
299
|
self._add_reflection()
|
|
302
300
|
|
|
303
301
|
# Start the server
|
|
304
|
-
logger.
|
|
302
|
+
logger.debug("Starting gRPC server on %s", self.config.address)
|
|
305
303
|
try:
|
|
306
304
|
if self.config.mode == ServerMode.ASYNC:
|
|
307
305
|
# For async server, use the event loop
|
|
@@ -314,7 +312,7 @@ class BaseServer(abc.ABC):
|
|
|
314
312
|
# For sync server, directly call start
|
|
315
313
|
sync_server = cast("grpc.Server", self.server)
|
|
316
314
|
sync_server.start()
|
|
317
|
-
logger.
|
|
315
|
+
logger.debug("✅ gRPC server started on %s", self.config.address)
|
|
318
316
|
except Exception as e:
|
|
319
317
|
logger.exception("❎ Error starting server")
|
|
320
318
|
msg = f"Failed to start server: {e}"
|
|
@@ -351,7 +349,7 @@ class BaseServer(abc.ABC):
|
|
|
351
349
|
self._add_reflection()
|
|
352
350
|
|
|
353
351
|
# Start the server
|
|
354
|
-
logger.
|
|
352
|
+
logger.debug("Starting gRPC server on %s", self.config.address)
|
|
355
353
|
try:
|
|
356
354
|
if self.config.mode == ServerMode.ASYNC:
|
|
357
355
|
await self._start_async()
|
|
@@ -359,7 +357,7 @@ class BaseServer(abc.ABC):
|
|
|
359
357
|
# For sync server in async context
|
|
360
358
|
sync_server = cast("grpc.Server", self.server)
|
|
361
359
|
sync_server.start()
|
|
362
|
-
logger.
|
|
360
|
+
logger.debug("✅ gRPC server started on %s", self.config.address)
|
|
363
361
|
except Exception as e:
|
|
364
362
|
logger.exception("❎ Error starting server")
|
|
365
363
|
msg = f"Failed to start server: {e}"
|
|
@@ -375,7 +373,7 @@ class BaseServer(abc.ABC):
|
|
|
375
373
|
logger.warning("Attempted to stop server, but no server is running")
|
|
376
374
|
return
|
|
377
375
|
|
|
378
|
-
logger.
|
|
376
|
+
logger.debug("Stopping gRPC server...")
|
|
379
377
|
if self.config.mode == ServerMode.ASYNC:
|
|
380
378
|
# We'll use a different approach that works whether we're in a running event loop or not
|
|
381
379
|
try:
|
|
@@ -392,13 +390,13 @@ class BaseServer(abc.ABC):
|
|
|
392
390
|
)
|
|
393
391
|
# Set server to None to avoid further operations
|
|
394
392
|
self.server = None
|
|
395
|
-
logger.
|
|
393
|
+
logger.debug("✅ gRPC server marked as stopped")
|
|
396
394
|
return
|
|
397
395
|
# If not in a running event loop, use run_until_complete
|
|
398
396
|
loop.run_until_complete(self._stop_async(grace))
|
|
399
397
|
except RuntimeError:
|
|
400
398
|
# Event loop issues - try with a new loop
|
|
401
|
-
logger.
|
|
399
|
+
logger.debug("Creating new event loop for shutdown")
|
|
402
400
|
try:
|
|
403
401
|
new_loop = asyncio.new_event_loop()
|
|
404
402
|
asyncio.set_event_loop(new_loop)
|
|
@@ -410,7 +408,7 @@ class BaseServer(abc.ABC):
|
|
|
410
408
|
sync_server = cast("grpc.Server", self.server)
|
|
411
409
|
sync_server.stop(grace=grace)
|
|
412
410
|
|
|
413
|
-
logger.
|
|
411
|
+
logger.debug("✅ gRPC server stopped")
|
|
414
412
|
self.server = None
|
|
415
413
|
|
|
416
414
|
async def _stop_async(self, grace: float | None = None) -> None:
|
|
@@ -437,7 +435,7 @@ class BaseServer(abc.ABC):
|
|
|
437
435
|
logger.warning("Attempted to stop server, but no server is running")
|
|
438
436
|
return
|
|
439
437
|
|
|
440
|
-
logger.
|
|
438
|
+
logger.debug("Stopping gRPC server asynchronously...")
|
|
441
439
|
if self.config.mode == ServerMode.ASYNC:
|
|
442
440
|
await self._stop_async(grace)
|
|
443
441
|
else:
|
|
@@ -445,7 +443,7 @@ class BaseServer(abc.ABC):
|
|
|
445
443
|
sync_server = cast("grpc.Server", self.server)
|
|
446
444
|
sync_server.stop(grace=grace)
|
|
447
445
|
|
|
448
|
-
logger.
|
|
446
|
+
logger.debug("✅ gRPC server stopped")
|
|
449
447
|
self.server = None
|
|
450
448
|
|
|
451
449
|
def wait_for_termination(self) -> None:
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Module gRPC server implementation for DigitalKin."""
|
|
2
2
|
|
|
3
|
-
import logging
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
import uuid
|
|
6
5
|
|
|
@@ -25,8 +24,7 @@ from digitalkin_proto.digitalkin.module_registry.v2 import (
|
|
|
25
24
|
module_registry_service_pb2_grpc,
|
|
26
25
|
registration_pb2,
|
|
27
26
|
)
|
|
28
|
-
|
|
29
|
-
logger = logging.getLogger(__name__)
|
|
27
|
+
from digitalkin.logger import logger
|
|
30
28
|
|
|
31
29
|
|
|
32
30
|
class ModuleServer(BaseServer):
|
|
@@ -70,14 +68,14 @@ class ModuleServer(BaseServer):
|
|
|
70
68
|
msg = "Server must be created before registering servicers"
|
|
71
69
|
raise RuntimeError(msg)
|
|
72
70
|
|
|
73
|
-
logger.
|
|
71
|
+
logger.debug("Registering module servicer for %s", self.module_class.__name__)
|
|
74
72
|
self.module_servicer = ModuleServicer(self.module_class)
|
|
75
73
|
self.register_servicer(
|
|
76
74
|
self.module_servicer,
|
|
77
75
|
module_service_pb2_grpc.add_ModuleServiceServicer_to_server,
|
|
78
76
|
service_descriptor=module_service_pb2.DESCRIPTOR,
|
|
79
77
|
)
|
|
80
|
-
logger.
|
|
78
|
+
logger.debug("Registered Module servicer")
|
|
81
79
|
|
|
82
80
|
def start(self) -> None:
|
|
83
81
|
"""Start the module server and register with the registry if configured."""
|
|
@@ -115,6 +113,7 @@ class ModuleServer(BaseServer):
|
|
|
115
113
|
logger.critical(
|
|
116
114
|
"Setup post init started with config: %s", self.client_config
|
|
117
115
|
)
|
|
116
|
+
await self.module_servicer.job_manager._start()
|
|
118
117
|
self.module_servicer.setup.__post_init__(self.client_config)
|
|
119
118
|
|
|
120
119
|
def stop(self, grace: float | None = None) -> None:
|
|
@@ -134,7 +133,7 @@ class ModuleServer(BaseServer):
|
|
|
134
133
|
Raises:
|
|
135
134
|
ServerError: If communication with the registry server fails.
|
|
136
135
|
"""
|
|
137
|
-
logger.
|
|
136
|
+
logger.debug(
|
|
138
137
|
"Registering module with registry at %s",
|
|
139
138
|
self.server_config.registry_address,
|
|
140
139
|
)
|
|
@@ -172,7 +171,7 @@ class ModuleServer(BaseServer):
|
|
|
172
171
|
|
|
173
172
|
try:
|
|
174
173
|
# Call the register method
|
|
175
|
-
logger.
|
|
174
|
+
logger.debug(
|
|
176
175
|
"Request sent to registry for module: %s:%s",
|
|
177
176
|
self.module_class.metadata["name"],
|
|
178
177
|
self.module_class.metadata["module_id"],
|
|
@@ -180,7 +179,7 @@ class ModuleServer(BaseServer):
|
|
|
180
179
|
response = stub.RegisterModule(request)
|
|
181
180
|
|
|
182
181
|
if response.success:
|
|
183
|
-
logger.
|
|
182
|
+
logger.debug("Module registered successfully")
|
|
184
183
|
else:
|
|
185
184
|
logger.error("Module registration failed")
|
|
186
185
|
except grpc.RpcError:
|
|
@@ -193,7 +192,7 @@ class ModuleServer(BaseServer):
|
|
|
193
192
|
Raises:
|
|
194
193
|
ServerError: If communication with the registry server fails.
|
|
195
194
|
"""
|
|
196
|
-
logger.
|
|
195
|
+
logger.debug(
|
|
197
196
|
"Deregistering module from registry at %s",
|
|
198
197
|
self.server_config.registry_address,
|
|
199
198
|
)
|
|
@@ -214,7 +213,7 @@ class ModuleServer(BaseServer):
|
|
|
214
213
|
response = stub.DeregisterModule(request)
|
|
215
214
|
|
|
216
215
|
if response.success:
|
|
217
|
-
logger.
|
|
216
|
+
logger.debug("Module deregistered successfull")
|
|
218
217
|
else:
|
|
219
218
|
logger.error("Module deregistration failed")
|
|
220
219
|
except grpc.RpcError:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Module servicer implementation for DigitalKin."""
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import logging
|
|
3
|
+
from argparse import ArgumentParser, Namespace
|
|
5
4
|
from collections.abc import AsyncGenerator
|
|
6
5
|
from typing import Any
|
|
7
6
|
|
|
@@ -15,19 +14,20 @@ from digitalkin_proto.digitalkin.module.v2 import (
|
|
|
15
14
|
from google.protobuf import json_format, struct_pb2
|
|
16
15
|
|
|
17
16
|
from digitalkin.grpc_servers.utils.exceptions import ServicerError
|
|
18
|
-
from digitalkin.
|
|
17
|
+
from digitalkin.logger import logger
|
|
19
18
|
from digitalkin.models.module.module import ModuleStatus
|
|
20
19
|
from digitalkin.modules._base_module import BaseModule
|
|
21
|
-
from digitalkin.modules.job_manager import
|
|
20
|
+
from digitalkin.modules.job_manager.base_job_manager import BaseJobManager
|
|
21
|
+
from digitalkin.modules.job_manager.job_manager_models import JobManagerMode
|
|
22
22
|
from digitalkin.services.services_models import ServicesMode
|
|
23
23
|
from digitalkin.services.setup.default_setup import DefaultSetup
|
|
24
24
|
from digitalkin.services.setup.grpc_setup import GrpcSetup
|
|
25
25
|
from digitalkin.services.setup.setup_strategy import SetupStrategy
|
|
26
|
+
from digitalkin.utils.arg_parser import ArgParser
|
|
27
|
+
from digitalkin.utils.development_mode_action import DevelopmentModeMappingAction
|
|
26
28
|
|
|
27
|
-
logger = logging.getLogger(__name__)
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
30
|
+
class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
|
|
31
31
|
"""Implementation of the ModuleService.
|
|
32
32
|
|
|
33
33
|
This servicer handles interactions with a DigitalKin module.
|
|
@@ -37,7 +37,31 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
37
37
|
active_jobs: Dictionary tracking active module jobs.
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
|
+
args: Namespace
|
|
40
41
|
setup: SetupStrategy
|
|
42
|
+
job_manager: BaseJobManager
|
|
43
|
+
|
|
44
|
+
def _add_parser_args(self, parser: ArgumentParser) -> None:
|
|
45
|
+
super()._add_parser_args(parser)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"-d",
|
|
48
|
+
"--dev-mode",
|
|
49
|
+
env_var="SERVICE_MODE",
|
|
50
|
+
choices=ServicesMode.__members__,
|
|
51
|
+
default="local",
|
|
52
|
+
action=DevelopmentModeMappingAction,
|
|
53
|
+
dest="services_mode",
|
|
54
|
+
help="Define Module Service configurations for endpoints",
|
|
55
|
+
)
|
|
56
|
+
parser.add_argument(
|
|
57
|
+
"-jm",
|
|
58
|
+
"--job-manager",
|
|
59
|
+
type=JobManagerMode,
|
|
60
|
+
choices=list(JobManagerMode),
|
|
61
|
+
default=JobManagerMode.SINGLE,
|
|
62
|
+
dest="job_manager_mode",
|
|
63
|
+
help="Define Module job manager configurations for load balancing",
|
|
64
|
+
)
|
|
41
65
|
|
|
42
66
|
def __init__(self, module_class: type[BaseModule]) -> None:
|
|
43
67
|
"""Initialize the module servicer.
|
|
@@ -46,15 +70,72 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
46
70
|
module_class: The module type to serve.
|
|
47
71
|
"""
|
|
48
72
|
super().__init__()
|
|
49
|
-
self.queue: asyncio.Queue = asyncio.Queue()
|
|
50
73
|
self.module_class = module_class
|
|
51
|
-
|
|
52
|
-
self.
|
|
74
|
+
job_manager_class = self.args.job_manager_mode.get_manager_class()
|
|
75
|
+
self.job_manager = job_manager_class(module_class, self.args.services_mode)
|
|
76
|
+
|
|
77
|
+
logger.debug(
|
|
78
|
+
"ModuleServicer initialized with job manager: %s | %s",
|
|
79
|
+
self.args.job_manager_mode,
|
|
80
|
+
self.job_manager,
|
|
81
|
+
)
|
|
82
|
+
self.setup = GrpcSetup() if self.args.services_mode == ServicesMode.REMOTE else DefaultSetup()
|
|
83
|
+
|
|
84
|
+
async def ConfigSetupModule( # noqa: N802
|
|
85
|
+
self,
|
|
86
|
+
request: lifecycle_pb2.ConfigSetupModuleRequest,
|
|
87
|
+
context: grpc.aio.ServicerContext,
|
|
88
|
+
) -> lifecycle_pb2.ConfigSetupModuleResponse:
|
|
89
|
+
"""Configure the module setup.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
request: The configuration request.
|
|
93
|
+
context: The gRPC context.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
A response indicating success or failure.
|
|
53
97
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
98
|
+
Raises:
|
|
99
|
+
ServicerError: if the setup data is not returned or job creation fails.
|
|
100
|
+
"""
|
|
101
|
+
logger.info("ConfigSetupVersion called for module: '%s'", self.module_class.__name__)
|
|
102
|
+
# Process the module input
|
|
103
|
+
# TODO: Secret should be used here as well
|
|
104
|
+
setup_version = request.setup_version
|
|
105
|
+
config_setup_data = self.module_class.create_config_setup_model(json_format.MessageToDict(request.content))
|
|
106
|
+
setup_version_data = self.module_class.create_setup_model(
|
|
107
|
+
json_format.MessageToDict(request.setup_version.content)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if not setup_version_data:
|
|
111
|
+
msg = "No setup data returned."
|
|
112
|
+
raise ServicerError(msg)
|
|
113
|
+
|
|
114
|
+
if not config_setup_data:
|
|
115
|
+
msg = "No config setup data returned."
|
|
116
|
+
raise ServicerError(msg)
|
|
117
|
+
|
|
118
|
+
# create a task to run the module in background
|
|
119
|
+
job_id = await self.job_manager.create_config_setup_instance_job(
|
|
120
|
+
config_setup_data,
|
|
121
|
+
setup_version_data,
|
|
122
|
+
request.mission_id,
|
|
123
|
+
setup_version.id,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if job_id is None:
|
|
127
|
+
context.set_code(grpc.StatusCode.NOT_FOUND)
|
|
128
|
+
context.set_details("Failed to create module instance")
|
|
129
|
+
return lifecycle_pb2.ConfigSetupModuleResponse(success=False)
|
|
130
|
+
|
|
131
|
+
updated_setup_data = await self.job_manager.generate_config_setup_module_response(job_id)
|
|
132
|
+
logger.warning(f"Updated setup data: {updated_setup_data=}")
|
|
133
|
+
setup_version.content = json_format.ParseDict(
|
|
134
|
+
updated_setup_data,
|
|
135
|
+
struct_pb2.Struct(),
|
|
136
|
+
ignore_unknown_fields=True,
|
|
137
|
+
)
|
|
138
|
+
return lifecycle_pb2.ConfigSetupModuleResponse(success=True, setup_version=setup_version)
|
|
58
139
|
|
|
59
140
|
async def StartModule( # noqa: N802
|
|
60
141
|
self,
|
|
@@ -87,47 +168,45 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
87
168
|
if not setup_data_class:
|
|
88
169
|
msg = "No setup data returned."
|
|
89
170
|
raise ServicerError(msg)
|
|
90
|
-
|
|
171
|
+
|
|
91
172
|
setup_data = self.module_class.create_setup_model(setup_data_class.current_setup_version.content)
|
|
92
173
|
|
|
93
|
-
#
|
|
94
|
-
|
|
95
|
-
result: tuple[str, BaseModule] = await self.job_manager.create_job(
|
|
174
|
+
# create a task to run the module in background
|
|
175
|
+
job_id = await self.job_manager.create_module_instance_job(
|
|
96
176
|
input_data,
|
|
97
177
|
setup_data,
|
|
98
178
|
mission_id=request.mission_id,
|
|
99
179
|
setup_version_id=setup_data_class.current_setup_version.id,
|
|
100
|
-
callback=self.add_to_queue,
|
|
101
180
|
)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
job_id=job_id
|
|
130
|
-
|
|
181
|
+
|
|
182
|
+
if job_id is None:
|
|
183
|
+
context.set_code(grpc.StatusCode.NOT_FOUND)
|
|
184
|
+
context.set_details("Failed to create module instance")
|
|
185
|
+
yield lifecycle_pb2.StartModuleResponse(success=False)
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
async with self.job_manager.generate_stream_consumer(job_id) as stream: # type: ignore
|
|
189
|
+
async for message in stream:
|
|
190
|
+
if message.get("error", None) is not None:
|
|
191
|
+
context.set_code(message["error"]["code"])
|
|
192
|
+
context.set_details(message["error"]["error_message"])
|
|
193
|
+
yield lifecycle_pb2.StartModuleResponse(success=False, job_id=job_id)
|
|
194
|
+
break
|
|
195
|
+
|
|
196
|
+
if message.get("exception", None) is not None:
|
|
197
|
+
logger.error("Error in output_data")
|
|
198
|
+
context.set_code(message["short_description"])
|
|
199
|
+
context.set_details(message["exception"])
|
|
200
|
+
yield lifecycle_pb2.StartModuleResponse(success=False, job_id=job_id)
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
if message.get("code", None) is not None and message.get("code") == "__END_OF_STREAM__":
|
|
204
|
+
yield lifecycle_pb2.StartModuleResponse(success=True, job_id=job_id)
|
|
205
|
+
break
|
|
206
|
+
|
|
207
|
+
proto = json_format.ParseDict(message, struct_pb2.Struct(), ignore_unknown_fields=True)
|
|
208
|
+
yield lifecycle_pb2.StartModuleResponse(success=True, output=proto, job_id=job_id)
|
|
209
|
+
logger.info("Job %s finished", job_id)
|
|
131
210
|
|
|
132
211
|
async def StopModule( # noqa: N802
|
|
133
212
|
self,
|
|
@@ -143,23 +222,20 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
143
222
|
Returns:
|
|
144
223
|
A response indicating success or failure.
|
|
145
224
|
"""
|
|
146
|
-
logger.
|
|
225
|
+
logger.debug("StopModule called for module: '%s'", self.module_class.__name__)
|
|
147
226
|
|
|
148
|
-
|
|
149
|
-
if
|
|
150
|
-
message = f"Job {job_id} not found"
|
|
227
|
+
response: bool = await self.job_manager.stop_module(request.job_id)
|
|
228
|
+
if not response:
|
|
229
|
+
message = f"Job {request.job_id} not found"
|
|
151
230
|
logger.warning(message)
|
|
152
231
|
context.set_code(grpc.StatusCode.NOT_FOUND)
|
|
153
232
|
context.set_details(message)
|
|
154
233
|
return lifecycle_pb2.StopModuleResponse(success=False)
|
|
155
234
|
|
|
156
|
-
|
|
157
|
-
await self.job_manager.modules[job_id].stop()
|
|
158
|
-
|
|
159
|
-
logger.info("Job %s stopped successfully", job_id)
|
|
235
|
+
logger.debug("Job %s stopped successfully", request.job_id)
|
|
160
236
|
return lifecycle_pb2.StopModuleResponse(success=True)
|
|
161
237
|
|
|
162
|
-
def GetModuleStatus( # noqa: N802
|
|
238
|
+
async def GetModuleStatus( # noqa: N802
|
|
163
239
|
self,
|
|
164
240
|
request: monitoring_pb2.GetModuleStatusRequest,
|
|
165
241
|
context: grpc.ServicerContext,
|
|
@@ -173,33 +249,33 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
173
249
|
Returns:
|
|
174
250
|
A response with the module status.
|
|
175
251
|
"""
|
|
176
|
-
logger.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if request.job_id not in self.job_manager.modules:
|
|
181
|
-
message = f"Job {request.job_id} not found"
|
|
182
|
-
logger.warning(message)
|
|
183
|
-
context.set_code(grpc.StatusCode.NOT_FOUND)
|
|
184
|
-
context.set_details(message)
|
|
185
|
-
return monitoring_pb2.GetModuleStatusResponse()
|
|
186
|
-
|
|
187
|
-
status = self.job_manager.modules[request.job_id].status
|
|
188
|
-
logger.info("Job %s status: '%s'", request.job_id, status)
|
|
252
|
+
logger.debug("GetModuleStatus called for module: '%s'", self.module_class.__name__)
|
|
253
|
+
|
|
254
|
+
if not request.job_id:
|
|
255
|
+
logger.debug("Job %s status: '%s'", request.job_id, ModuleStatus.NOT_FOUND)
|
|
189
256
|
return monitoring_pb2.GetModuleStatusResponse(
|
|
190
|
-
success=
|
|
191
|
-
status=
|
|
257
|
+
success=False,
|
|
258
|
+
status=ModuleStatus.NOT_FOUND.name,
|
|
192
259
|
job_id=request.job_id,
|
|
193
260
|
)
|
|
194
261
|
|
|
195
|
-
|
|
262
|
+
status = await self.job_manager.get_module_status(request.job_id)
|
|
263
|
+
|
|
264
|
+
if status is None:
|
|
265
|
+
message = f"Job {request.job_id} not found"
|
|
266
|
+
logger.warning(message)
|
|
267
|
+
context.set_code(grpc.StatusCode.NOT_FOUND)
|
|
268
|
+
context.set_details(message)
|
|
269
|
+
return monitoring_pb2.GetModuleStatusResponse()
|
|
270
|
+
|
|
271
|
+
logger.debug("Job %s status: '%s'", request.job_id, status)
|
|
196
272
|
return monitoring_pb2.GetModuleStatusResponse(
|
|
197
|
-
success=
|
|
198
|
-
status=
|
|
273
|
+
success=True,
|
|
274
|
+
status=status.name,
|
|
199
275
|
job_id=request.job_id,
|
|
200
276
|
)
|
|
201
277
|
|
|
202
|
-
def GetModuleJobs( # noqa: N802
|
|
278
|
+
async def GetModuleJobs( # noqa: N802
|
|
203
279
|
self,
|
|
204
280
|
request: monitoring_pb2.GetModuleJobsRequest, # noqa: ARG002
|
|
205
281
|
context: grpc.ServicerContext, # noqa: ARG002
|
|
@@ -213,20 +289,22 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
213
289
|
Returns:
|
|
214
290
|
A response with information about active jobs.
|
|
215
291
|
"""
|
|
216
|
-
logger.
|
|
292
|
+
logger.debug("GetModuleJobs called for module: '%s'", self.module_class.__name__)
|
|
293
|
+
|
|
294
|
+
modules = await self.job_manager.list_modules()
|
|
217
295
|
|
|
218
296
|
# Create job info objects for each active job
|
|
219
297
|
return monitoring_pb2.GetModuleJobsResponse(
|
|
220
298
|
jobs=[
|
|
221
299
|
monitoring_pb2.JobInfo(
|
|
222
300
|
job_id=job_id,
|
|
223
|
-
job_status=job_data
|
|
301
|
+
job_status=job_data["status"].name,
|
|
224
302
|
)
|
|
225
|
-
for job_id, job_data in
|
|
303
|
+
for job_id, job_data in modules.items()
|
|
226
304
|
],
|
|
227
305
|
)
|
|
228
306
|
|
|
229
|
-
def GetModuleInput( # noqa: N802
|
|
307
|
+
async def GetModuleInput( # noqa: N802
|
|
230
308
|
self,
|
|
231
309
|
request: information_pb2.GetModuleInputRequest,
|
|
232
310
|
context: grpc.ServicerContext,
|
|
@@ -240,7 +318,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
240
318
|
Returns:
|
|
241
319
|
A response with the module's input schema.
|
|
242
320
|
"""
|
|
243
|
-
logger.
|
|
321
|
+
logger.debug("GetModuleInput called for module: '%s'", self.module_class.__name__)
|
|
244
322
|
|
|
245
323
|
# Get input schema if available
|
|
246
324
|
try:
|
|
@@ -262,7 +340,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
262
340
|
input_schema=input_format_struct,
|
|
263
341
|
)
|
|
264
342
|
|
|
265
|
-
def GetModuleOutput( # noqa: N802
|
|
343
|
+
async def GetModuleOutput( # noqa: N802
|
|
266
344
|
self,
|
|
267
345
|
request: information_pb2.GetModuleOutputRequest,
|
|
268
346
|
context: grpc.ServicerContext,
|
|
@@ -276,7 +354,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
276
354
|
Returns:
|
|
277
355
|
A response with the module's output schema.
|
|
278
356
|
"""
|
|
279
|
-
logger.
|
|
357
|
+
logger.debug("GetModuleOutput called for module: '%s'", self.module_class.__name__)
|
|
280
358
|
|
|
281
359
|
# Get output schema if available
|
|
282
360
|
try:
|
|
@@ -298,7 +376,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
298
376
|
output_schema=output_format_struct,
|
|
299
377
|
)
|
|
300
378
|
|
|
301
|
-
def GetModuleSetup( # noqa: N802
|
|
379
|
+
async def GetModuleSetup( # noqa: N802
|
|
302
380
|
self,
|
|
303
381
|
request: information_pb2.GetModuleSetupRequest,
|
|
304
382
|
context: grpc.ServicerContext,
|
|
@@ -312,7 +390,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
312
390
|
Returns:
|
|
313
391
|
A response with the module's setup information.
|
|
314
392
|
"""
|
|
315
|
-
logger.
|
|
393
|
+
logger.debug("GetModuleSetup called for module: '%s'", self.module_class.__name__)
|
|
316
394
|
|
|
317
395
|
# Get setup schema if available
|
|
318
396
|
try:
|
|
@@ -369,3 +447,39 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer):
|
|
|
369
447
|
success=True,
|
|
370
448
|
secret_schema=secret_format_struct,
|
|
371
449
|
)
|
|
450
|
+
|
|
451
|
+
async def GetConfigSetupModule( # noqa: N802
|
|
452
|
+
self,
|
|
453
|
+
request: information_pb2.GetConfigSetupModuleRequest,
|
|
454
|
+
context: grpc.ServicerContext,
|
|
455
|
+
) -> information_pb2.GetConfigSetupModuleResponse:
|
|
456
|
+
"""Get information about the module's setup and configuration.
|
|
457
|
+
|
|
458
|
+
Args:
|
|
459
|
+
request: The get module setup request.
|
|
460
|
+
context: The gRPC context.
|
|
461
|
+
|
|
462
|
+
Returns:
|
|
463
|
+
A response with the module's setup information.
|
|
464
|
+
"""
|
|
465
|
+
logger.debug("GetConfigSetupModule called for module: '%s'", self.module_class.__name__)
|
|
466
|
+
|
|
467
|
+
# Get setup schema if available
|
|
468
|
+
try:
|
|
469
|
+
# Convert schema to proto format
|
|
470
|
+
config_setup_schema_proto = self.module_class.get_config_setup_format(llm_format=request.llm_format)
|
|
471
|
+
config_setup_format_struct = json_format.Parse(
|
|
472
|
+
text=config_setup_schema_proto,
|
|
473
|
+
message=struct_pb2.Struct(), # pylint: disable=no-member
|
|
474
|
+
ignore_unknown_fields=True,
|
|
475
|
+
)
|
|
476
|
+
except NotImplementedError as e:
|
|
477
|
+
logger.warning(e)
|
|
478
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
479
|
+
context.set_details(e)
|
|
480
|
+
return information_pb2.GetConfigSetupModuleResponse()
|
|
481
|
+
|
|
482
|
+
return information_pb2.GetConfigSetupModuleResponse(
|
|
483
|
+
success=True,
|
|
484
|
+
config_setup_schema=config_setup_format_struct,
|
|
485
|
+
)
|