flwr-nightly 1.13.0.dev20241113__py3-none-any.whl → 1.13.0.dev20241114__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 flwr-nightly might be problematic. Click here for more details.
- flwr/cli/app.py +2 -0
- flwr/cli/ls.py +228 -0
- flwr/client/app.py +20 -3
- flwr/client/clientapp/app.py +6 -2
- flwr/client/grpc_rere_client/connection.py +2 -12
- flwr/client/rest_client/connection.py +4 -14
- flwr/client/supernode/app.py +27 -1
- flwr/common/serde.py +10 -0
- flwr/common/typing.py +31 -10
- flwr/proto/exec_pb2.py +22 -13
- flwr/proto/exec_pb2.pyi +44 -0
- flwr/proto/exec_pb2_grpc.py +34 -0
- flwr/proto/exec_pb2_grpc.pyi +13 -0
- flwr/proto/run_pb2.py +30 -30
- flwr/proto/run_pb2.pyi +18 -1
- flwr/server/driver/grpc_driver.py +2 -12
- flwr/server/superlink/fleet/rest_rere/rest_api.py +10 -9
- flwr/server/superlink/linkstate/in_memory_linkstate.py +16 -18
- flwr/server/superlink/linkstate/sqlite_linkstate.py +9 -0
- flwr/simulation/run_simulation.py +7 -18
- flwr/superexec/exec_servicer.py +31 -2
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241114.dist-info}/METADATA +1 -1
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241114.dist-info}/RECORD +26 -25
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241114.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241114.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241114.dist-info}/entry_points.txt +0 -0
flwr/proto/exec_pb2_grpc.py
CHANGED
|
@@ -24,6 +24,11 @@ class ExecStub(object):
|
|
|
24
24
|
request_serializer=flwr_dot_proto_dot_exec__pb2.StreamLogsRequest.SerializeToString,
|
|
25
25
|
response_deserializer=flwr_dot_proto_dot_exec__pb2.StreamLogsResponse.FromString,
|
|
26
26
|
)
|
|
27
|
+
self.ListRuns = channel.unary_unary(
|
|
28
|
+
'/flwr.proto.Exec/ListRuns',
|
|
29
|
+
request_serializer=flwr_dot_proto_dot_exec__pb2.ListRunsRequest.SerializeToString,
|
|
30
|
+
response_deserializer=flwr_dot_proto_dot_exec__pb2.ListRunsResponse.FromString,
|
|
31
|
+
)
|
|
27
32
|
|
|
28
33
|
|
|
29
34
|
class ExecServicer(object):
|
|
@@ -43,6 +48,13 @@ class ExecServicer(object):
|
|
|
43
48
|
context.set_details('Method not implemented!')
|
|
44
49
|
raise NotImplementedError('Method not implemented!')
|
|
45
50
|
|
|
51
|
+
def ListRuns(self, request, context):
|
|
52
|
+
"""flwr ls command
|
|
53
|
+
"""
|
|
54
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
55
|
+
context.set_details('Method not implemented!')
|
|
56
|
+
raise NotImplementedError('Method not implemented!')
|
|
57
|
+
|
|
46
58
|
|
|
47
59
|
def add_ExecServicer_to_server(servicer, server):
|
|
48
60
|
rpc_method_handlers = {
|
|
@@ -56,6 +68,11 @@ def add_ExecServicer_to_server(servicer, server):
|
|
|
56
68
|
request_deserializer=flwr_dot_proto_dot_exec__pb2.StreamLogsRequest.FromString,
|
|
57
69
|
response_serializer=flwr_dot_proto_dot_exec__pb2.StreamLogsResponse.SerializeToString,
|
|
58
70
|
),
|
|
71
|
+
'ListRuns': grpc.unary_unary_rpc_method_handler(
|
|
72
|
+
servicer.ListRuns,
|
|
73
|
+
request_deserializer=flwr_dot_proto_dot_exec__pb2.ListRunsRequest.FromString,
|
|
74
|
+
response_serializer=flwr_dot_proto_dot_exec__pb2.ListRunsResponse.SerializeToString,
|
|
75
|
+
),
|
|
59
76
|
}
|
|
60
77
|
generic_handler = grpc.method_handlers_generic_handler(
|
|
61
78
|
'flwr.proto.Exec', rpc_method_handlers)
|
|
@@ -99,3 +116,20 @@ class Exec(object):
|
|
|
99
116
|
flwr_dot_proto_dot_exec__pb2.StreamLogsResponse.FromString,
|
|
100
117
|
options, channel_credentials,
|
|
101
118
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def ListRuns(request,
|
|
122
|
+
target,
|
|
123
|
+
options=(),
|
|
124
|
+
channel_credentials=None,
|
|
125
|
+
call_credentials=None,
|
|
126
|
+
insecure=False,
|
|
127
|
+
compression=None,
|
|
128
|
+
wait_for_ready=None,
|
|
129
|
+
timeout=None,
|
|
130
|
+
metadata=None):
|
|
131
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.Exec/ListRuns',
|
|
132
|
+
flwr_dot_proto_dot_exec__pb2.ListRunsRequest.SerializeToString,
|
|
133
|
+
flwr_dot_proto_dot_exec__pb2.ListRunsResponse.FromString,
|
|
134
|
+
options, channel_credentials,
|
|
135
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
flwr/proto/exec_pb2_grpc.pyi
CHANGED
|
@@ -19,6 +19,11 @@ class ExecStub:
|
|
|
19
19
|
flwr.proto.exec_pb2.StreamLogsResponse]
|
|
20
20
|
"""Start log stream upon request"""
|
|
21
21
|
|
|
22
|
+
ListRuns: grpc.UnaryUnaryMultiCallable[
|
|
23
|
+
flwr.proto.exec_pb2.ListRunsRequest,
|
|
24
|
+
flwr.proto.exec_pb2.ListRunsResponse]
|
|
25
|
+
"""flwr ls command"""
|
|
26
|
+
|
|
22
27
|
|
|
23
28
|
class ExecServicer(metaclass=abc.ABCMeta):
|
|
24
29
|
@abc.abstractmethod
|
|
@@ -37,5 +42,13 @@ class ExecServicer(metaclass=abc.ABCMeta):
|
|
|
37
42
|
"""Start log stream upon request"""
|
|
38
43
|
pass
|
|
39
44
|
|
|
45
|
+
@abc.abstractmethod
|
|
46
|
+
def ListRuns(self,
|
|
47
|
+
request: flwr.proto.exec_pb2.ListRunsRequest,
|
|
48
|
+
context: grpc.ServicerContext,
|
|
49
|
+
) -> flwr.proto.exec_pb2.ListRunsResponse:
|
|
50
|
+
"""flwr ls command"""
|
|
51
|
+
pass
|
|
52
|
+
|
|
40
53
|
|
|
41
54
|
def add_ExecServicer_to_server(servicer: ExecServicer, server: grpc.Server) -> None: ...
|
flwr/proto/run_pb2.py
CHANGED
|
@@ -18,7 +18,7 @@ from flwr.proto import recordset_pb2 as flwr_dot_proto_dot_recordset__pb2
|
|
|
18
18
|
from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x66lwr/proto/run.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x1a\x66lwr/proto/recordset.proto\x1a\x1a\x66lwr/proto/transport.proto\"\
|
|
21
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x66lwr/proto/run.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x1a\x66lwr/proto/recordset.proto\x1a\x1a\x66lwr/proto/transport.proto\"\xce\x02\n\x03Run\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x0e\n\x06\x66\x61\x62_id\x18\x02 \x01(\t\x12\x13\n\x0b\x66\x61\x62_version\x18\x03 \x01(\t\x12<\n\x0foverride_config\x18\x04 \x03(\x0b\x32#.flwr.proto.Run.OverrideConfigEntry\x12\x10\n\x08\x66\x61\x62_hash\x18\x05 \x01(\t\x12\x12\n\npending_at\x18\x06 \x01(\t\x12\x13\n\x0bstarting_at\x18\x07 \x01(\t\x12\x12\n\nrunning_at\x18\x08 \x01(\t\x12\x13\n\x0b\x66inished_at\x18\t \x01(\t\x12%\n\x06status\x18\n \x01(\x0b\x32\x15.flwr.proto.RunStatus\x1aI\n\x13OverrideConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"@\n\tRunStatus\x12\x0e\n\x06status\x18\x01 \x01(\t\x12\x12\n\nsub_status\x18\x02 \x01(\t\x12\x0f\n\x07\x64\x65tails\x18\x03 \x01(\t\"\xeb\x01\n\x10\x43reateRunRequest\x12\x0e\n\x06\x66\x61\x62_id\x18\x01 \x01(\t\x12\x13\n\x0b\x66\x61\x62_version\x18\x02 \x01(\t\x12I\n\x0foverride_config\x18\x03 \x03(\x0b\x32\x30.flwr.proto.CreateRunRequest.OverrideConfigEntry\x12\x1c\n\x03\x66\x61\x62\x18\x04 \x01(\x0b\x32\x0f.flwr.proto.Fab\x1aI\n\x13OverrideConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"#\n\x11\x43reateRunResponse\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"?\n\rGetRunRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\".\n\x0eGetRunResponse\x12\x1c\n\x03run\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Run\"S\n\x16UpdateRunStatusRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12)\n\nrun_status\x18\x02 \x01(\x0b\x32\x15.flwr.proto.RunStatus\"\x19\n\x17UpdateRunStatusResponse\"F\n\x13GetRunStatusRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0f\n\x07run_ids\x18\x02 \x03(\x04\"\xb1\x01\n\x14GetRunStatusResponse\x12L\n\x0frun_status_dict\x18\x01 \x03(\x0b\x32\x33.flwr.proto.GetRunStatusResponse.RunStatusDictEntry\x1aK\n\x12RunStatusDictEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.RunStatus:\x02\x38\x01\"-\n\x1bGetFederationOptionsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"U\n\x1cGetFederationOptionsResponse\x12\x35\n\x12\x66\x65\x64\x65ration_options\x18\x01 \x01(\x0b\x32\x19.flwr.proto.ConfigsRecordb\x06proto3')
|
|
22
22
|
|
|
23
23
|
_globals = globals()
|
|
24
24
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -32,33 +32,33 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
32
32
|
_globals['_GETRUNSTATUSRESPONSE_RUNSTATUSDICTENTRY']._options = None
|
|
33
33
|
_globals['_GETRUNSTATUSRESPONSE_RUNSTATUSDICTENTRY']._serialized_options = b'8\001'
|
|
34
34
|
_globals['_RUN']._serialized_start=138
|
|
35
|
-
_globals['_RUN']._serialized_end=
|
|
36
|
-
_globals['_RUN_OVERRIDECONFIGENTRY']._serialized_start=
|
|
37
|
-
_globals['_RUN_OVERRIDECONFIGENTRY']._serialized_end=
|
|
38
|
-
_globals['_RUNSTATUS']._serialized_start=
|
|
39
|
-
_globals['_RUNSTATUS']._serialized_end=
|
|
40
|
-
_globals['_CREATERUNREQUEST']._serialized_start=
|
|
41
|
-
_globals['_CREATERUNREQUEST']._serialized_end=
|
|
42
|
-
_globals['_CREATERUNREQUEST_OVERRIDECONFIGENTRY']._serialized_start=
|
|
43
|
-
_globals['_CREATERUNREQUEST_OVERRIDECONFIGENTRY']._serialized_end=
|
|
44
|
-
_globals['_CREATERUNRESPONSE']._serialized_start=
|
|
45
|
-
_globals['_CREATERUNRESPONSE']._serialized_end=
|
|
46
|
-
_globals['_GETRUNREQUEST']._serialized_start=
|
|
47
|
-
_globals['_GETRUNREQUEST']._serialized_end=
|
|
48
|
-
_globals['_GETRUNRESPONSE']._serialized_start=
|
|
49
|
-
_globals['_GETRUNRESPONSE']._serialized_end=
|
|
50
|
-
_globals['_UPDATERUNSTATUSREQUEST']._serialized_start=
|
|
51
|
-
_globals['_UPDATERUNSTATUSREQUEST']._serialized_end=
|
|
52
|
-
_globals['_UPDATERUNSTATUSRESPONSE']._serialized_start=
|
|
53
|
-
_globals['_UPDATERUNSTATUSRESPONSE']._serialized_end=
|
|
54
|
-
_globals['_GETRUNSTATUSREQUEST']._serialized_start=
|
|
55
|
-
_globals['_GETRUNSTATUSREQUEST']._serialized_end=
|
|
56
|
-
_globals['_GETRUNSTATUSRESPONSE']._serialized_start=
|
|
57
|
-
_globals['_GETRUNSTATUSRESPONSE']._serialized_end=
|
|
58
|
-
_globals['_GETRUNSTATUSRESPONSE_RUNSTATUSDICTENTRY']._serialized_start=
|
|
59
|
-
_globals['_GETRUNSTATUSRESPONSE_RUNSTATUSDICTENTRY']._serialized_end=
|
|
60
|
-
_globals['_GETFEDERATIONOPTIONSREQUEST']._serialized_start=
|
|
61
|
-
_globals['_GETFEDERATIONOPTIONSREQUEST']._serialized_end=
|
|
62
|
-
_globals['_GETFEDERATIONOPTIONSRESPONSE']._serialized_start=
|
|
63
|
-
_globals['_GETFEDERATIONOPTIONSRESPONSE']._serialized_end=
|
|
35
|
+
_globals['_RUN']._serialized_end=472
|
|
36
|
+
_globals['_RUN_OVERRIDECONFIGENTRY']._serialized_start=399
|
|
37
|
+
_globals['_RUN_OVERRIDECONFIGENTRY']._serialized_end=472
|
|
38
|
+
_globals['_RUNSTATUS']._serialized_start=474
|
|
39
|
+
_globals['_RUNSTATUS']._serialized_end=538
|
|
40
|
+
_globals['_CREATERUNREQUEST']._serialized_start=541
|
|
41
|
+
_globals['_CREATERUNREQUEST']._serialized_end=776
|
|
42
|
+
_globals['_CREATERUNREQUEST_OVERRIDECONFIGENTRY']._serialized_start=399
|
|
43
|
+
_globals['_CREATERUNREQUEST_OVERRIDECONFIGENTRY']._serialized_end=472
|
|
44
|
+
_globals['_CREATERUNRESPONSE']._serialized_start=778
|
|
45
|
+
_globals['_CREATERUNRESPONSE']._serialized_end=813
|
|
46
|
+
_globals['_GETRUNREQUEST']._serialized_start=815
|
|
47
|
+
_globals['_GETRUNREQUEST']._serialized_end=878
|
|
48
|
+
_globals['_GETRUNRESPONSE']._serialized_start=880
|
|
49
|
+
_globals['_GETRUNRESPONSE']._serialized_end=926
|
|
50
|
+
_globals['_UPDATERUNSTATUSREQUEST']._serialized_start=928
|
|
51
|
+
_globals['_UPDATERUNSTATUSREQUEST']._serialized_end=1011
|
|
52
|
+
_globals['_UPDATERUNSTATUSRESPONSE']._serialized_start=1013
|
|
53
|
+
_globals['_UPDATERUNSTATUSRESPONSE']._serialized_end=1038
|
|
54
|
+
_globals['_GETRUNSTATUSREQUEST']._serialized_start=1040
|
|
55
|
+
_globals['_GETRUNSTATUSREQUEST']._serialized_end=1110
|
|
56
|
+
_globals['_GETRUNSTATUSRESPONSE']._serialized_start=1113
|
|
57
|
+
_globals['_GETRUNSTATUSRESPONSE']._serialized_end=1290
|
|
58
|
+
_globals['_GETRUNSTATUSRESPONSE_RUNSTATUSDICTENTRY']._serialized_start=1215
|
|
59
|
+
_globals['_GETRUNSTATUSRESPONSE_RUNSTATUSDICTENTRY']._serialized_end=1290
|
|
60
|
+
_globals['_GETFEDERATIONOPTIONSREQUEST']._serialized_start=1292
|
|
61
|
+
_globals['_GETFEDERATIONOPTIONSREQUEST']._serialized_end=1337
|
|
62
|
+
_globals['_GETFEDERATIONOPTIONSRESPONSE']._serialized_start=1339
|
|
63
|
+
_globals['_GETFEDERATIONOPTIONSRESPONSE']._serialized_end=1424
|
|
64
64
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/run_pb2.pyi
CHANGED
|
@@ -37,12 +37,23 @@ class Run(google.protobuf.message.Message):
|
|
|
37
37
|
FAB_VERSION_FIELD_NUMBER: builtins.int
|
|
38
38
|
OVERRIDE_CONFIG_FIELD_NUMBER: builtins.int
|
|
39
39
|
FAB_HASH_FIELD_NUMBER: builtins.int
|
|
40
|
+
PENDING_AT_FIELD_NUMBER: builtins.int
|
|
41
|
+
STARTING_AT_FIELD_NUMBER: builtins.int
|
|
42
|
+
RUNNING_AT_FIELD_NUMBER: builtins.int
|
|
43
|
+
FINISHED_AT_FIELD_NUMBER: builtins.int
|
|
44
|
+
STATUS_FIELD_NUMBER: builtins.int
|
|
40
45
|
run_id: builtins.int
|
|
41
46
|
fab_id: typing.Text
|
|
42
47
|
fab_version: typing.Text
|
|
43
48
|
@property
|
|
44
49
|
def override_config(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, flwr.proto.transport_pb2.Scalar]: ...
|
|
45
50
|
fab_hash: typing.Text
|
|
51
|
+
pending_at: typing.Text
|
|
52
|
+
starting_at: typing.Text
|
|
53
|
+
running_at: typing.Text
|
|
54
|
+
finished_at: typing.Text
|
|
55
|
+
@property
|
|
56
|
+
def status(self) -> global___RunStatus: ...
|
|
46
57
|
def __init__(self,
|
|
47
58
|
*,
|
|
48
59
|
run_id: builtins.int = ...,
|
|
@@ -50,8 +61,14 @@ class Run(google.protobuf.message.Message):
|
|
|
50
61
|
fab_version: typing.Text = ...,
|
|
51
62
|
override_config: typing.Optional[typing.Mapping[typing.Text, flwr.proto.transport_pb2.Scalar]] = ...,
|
|
52
63
|
fab_hash: typing.Text = ...,
|
|
64
|
+
pending_at: typing.Text = ...,
|
|
65
|
+
starting_at: typing.Text = ...,
|
|
66
|
+
running_at: typing.Text = ...,
|
|
67
|
+
finished_at: typing.Text = ...,
|
|
68
|
+
status: typing.Optional[global___RunStatus] = ...,
|
|
53
69
|
) -> None: ...
|
|
54
|
-
def
|
|
70
|
+
def HasField(self, field_name: typing_extensions.Literal["status",b"status"]) -> builtins.bool: ...
|
|
71
|
+
def ClearField(self, field_name: typing_extensions.Literal["fab_hash",b"fab_hash","fab_id",b"fab_id","fab_version",b"fab_version","finished_at",b"finished_at","override_config",b"override_config","pending_at",b"pending_at","run_id",b"run_id","running_at",b"running_at","starting_at",b"starting_at","status",b"status"]) -> None: ...
|
|
55
72
|
global___Run = Run
|
|
56
73
|
|
|
57
74
|
class RunStatus(google.protobuf.message.Message):
|
|
@@ -26,11 +26,7 @@ from flwr.common import DEFAULT_TTL, Message, Metadata, RecordSet
|
|
|
26
26
|
from flwr.common.constant import SERVERAPPIO_API_DEFAULT_ADDRESS
|
|
27
27
|
from flwr.common.grpc import create_channel
|
|
28
28
|
from flwr.common.logger import log
|
|
29
|
-
from flwr.common.serde import
|
|
30
|
-
message_from_taskres,
|
|
31
|
-
message_to_taskins,
|
|
32
|
-
user_config_from_proto,
|
|
33
|
-
)
|
|
29
|
+
from flwr.common.serde import message_from_taskres, message_to_taskins, run_from_proto
|
|
34
30
|
from flwr.common.typing import Run
|
|
35
31
|
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
36
32
|
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
@@ -119,13 +115,7 @@ class GrpcDriver(Driver):
|
|
|
119
115
|
res: GetRunResponse = self._stub.GetRun(req)
|
|
120
116
|
if not res.HasField("run"):
|
|
121
117
|
raise RuntimeError(f"Cannot find the run with ID: {run_id}")
|
|
122
|
-
self._run =
|
|
123
|
-
run_id=res.run.run_id,
|
|
124
|
-
fab_id=res.run.fab_id,
|
|
125
|
-
fab_version=res.run.fab_version,
|
|
126
|
-
fab_hash=res.run.fab_hash,
|
|
127
|
-
override_config=user_config_from_proto(res.run.override_config),
|
|
128
|
-
)
|
|
118
|
+
self._run = run_from_proto(res.run)
|
|
129
119
|
|
|
130
120
|
@property
|
|
131
121
|
def run(self) -> Run:
|
|
@@ -19,7 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import sys
|
|
21
21
|
from collections.abc import Awaitable
|
|
22
|
-
from typing import Callable, TypeVar
|
|
22
|
+
from typing import Callable, TypeVar, cast
|
|
23
23
|
|
|
24
24
|
from google.protobuf.message import Message as GrpcMessage
|
|
25
25
|
|
|
@@ -39,8 +39,9 @@ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
|
39
39
|
)
|
|
40
40
|
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
41
41
|
from flwr.server.superlink.ffs.ffs import Ffs
|
|
42
|
+
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
42
43
|
from flwr.server.superlink.fleet.message_handler import message_handler
|
|
43
|
-
from flwr.server.superlink.linkstate import LinkState
|
|
44
|
+
from flwr.server.superlink.linkstate import LinkState, LinkStateFactory
|
|
44
45
|
|
|
45
46
|
try:
|
|
46
47
|
from starlette.applications import Starlette
|
|
@@ -90,7 +91,7 @@ def rest_request_response(
|
|
|
90
91
|
async def create_node(request: CreateNodeRequest) -> CreateNodeResponse:
|
|
91
92
|
"""Create Node."""
|
|
92
93
|
# Get state from app
|
|
93
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
94
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
94
95
|
|
|
95
96
|
# Handle message
|
|
96
97
|
return message_handler.create_node(request=request, state=state)
|
|
@@ -100,7 +101,7 @@ async def create_node(request: CreateNodeRequest) -> CreateNodeResponse:
|
|
|
100
101
|
async def delete_node(request: DeleteNodeRequest) -> DeleteNodeResponse:
|
|
101
102
|
"""Delete Node Id."""
|
|
102
103
|
# Get state from app
|
|
103
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
104
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
104
105
|
|
|
105
106
|
# Handle message
|
|
106
107
|
return message_handler.delete_node(request=request, state=state)
|
|
@@ -110,7 +111,7 @@ async def delete_node(request: DeleteNodeRequest) -> DeleteNodeResponse:
|
|
|
110
111
|
async def pull_task_ins(request: PullTaskInsRequest) -> PullTaskInsResponse:
|
|
111
112
|
"""Pull TaskIns."""
|
|
112
113
|
# Get state from app
|
|
113
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
114
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
114
115
|
|
|
115
116
|
# Handle message
|
|
116
117
|
return message_handler.pull_task_ins(request=request, state=state)
|
|
@@ -121,7 +122,7 @@ async def pull_task_ins(request: PullTaskInsRequest) -> PullTaskInsResponse:
|
|
|
121
122
|
async def push_task_res(request: PushTaskResRequest) -> PushTaskResResponse:
|
|
122
123
|
"""Push TaskRes."""
|
|
123
124
|
# Get state from app
|
|
124
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
125
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
125
126
|
|
|
126
127
|
# Handle message
|
|
127
128
|
return message_handler.push_task_res(request=request, state=state)
|
|
@@ -131,7 +132,7 @@ async def push_task_res(request: PushTaskResRequest) -> PushTaskResResponse:
|
|
|
131
132
|
async def ping(request: PingRequest) -> PingResponse:
|
|
132
133
|
"""Ping."""
|
|
133
134
|
# Get state from app
|
|
134
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
135
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
135
136
|
|
|
136
137
|
# Handle message
|
|
137
138
|
return message_handler.ping(request=request, state=state)
|
|
@@ -141,7 +142,7 @@ async def ping(request: PingRequest) -> PingResponse:
|
|
|
141
142
|
async def get_run(request: GetRunRequest) -> GetRunResponse:
|
|
142
143
|
"""GetRun."""
|
|
143
144
|
# Get state from app
|
|
144
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
145
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
145
146
|
|
|
146
147
|
# Handle message
|
|
147
148
|
return message_handler.get_run(request=request, state=state)
|
|
@@ -151,7 +152,7 @@ async def get_run(request: GetRunRequest) -> GetRunResponse:
|
|
|
151
152
|
async def get_fab(request: GetFabRequest) -> GetFabResponse:
|
|
152
153
|
"""GetRun."""
|
|
153
154
|
# Get ffs from app
|
|
154
|
-
ffs: Ffs = app.state.FFS_FACTORY.
|
|
155
|
+
ffs: Ffs = cast(FfsFactory, app.state.FFS_FACTORY).ffs()
|
|
155
156
|
|
|
156
157
|
# Handle message
|
|
157
158
|
return message_handler.get_fab(request=request, ffs=ffs)
|
|
@@ -48,11 +48,6 @@ class RunRecord: # pylint: disable=R0902
|
|
|
48
48
|
"""The record of a specific run, including its status and timestamps."""
|
|
49
49
|
|
|
50
50
|
run: Run
|
|
51
|
-
status: RunStatus
|
|
52
|
-
pending_at: str = ""
|
|
53
|
-
starting_at: str = ""
|
|
54
|
-
running_at: str = ""
|
|
55
|
-
finished_at: str = ""
|
|
56
51
|
logs: list[tuple[float, str]] = field(default_factory=list)
|
|
57
52
|
log_lock: threading.Lock = field(default_factory=threading.Lock)
|
|
58
53
|
|
|
@@ -386,13 +381,16 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
386
381
|
fab_version=fab_version if fab_version else "",
|
|
387
382
|
fab_hash=fab_hash if fab_hash else "",
|
|
388
383
|
override_config=override_config,
|
|
384
|
+
pending_at=now().isoformat(),
|
|
385
|
+
starting_at="",
|
|
386
|
+
running_at="",
|
|
387
|
+
finished_at="",
|
|
388
|
+
status=RunStatus(
|
|
389
|
+
status=Status.PENDING,
|
|
390
|
+
sub_status="",
|
|
391
|
+
details="",
|
|
392
|
+
),
|
|
389
393
|
),
|
|
390
|
-
status=RunStatus(
|
|
391
|
-
status=Status.PENDING,
|
|
392
|
-
sub_status="",
|
|
393
|
-
details="",
|
|
394
|
-
),
|
|
395
|
-
pending_at=now().isoformat(),
|
|
396
394
|
)
|
|
397
395
|
self.run_ids[run_id] = run_record
|
|
398
396
|
|
|
@@ -452,7 +450,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
452
450
|
"""Retrieve the statuses for the specified runs."""
|
|
453
451
|
with self.lock:
|
|
454
452
|
return {
|
|
455
|
-
run_id: self.run_ids[run_id].status
|
|
453
|
+
run_id: self.run_ids[run_id].run.status
|
|
456
454
|
for run_id in set(run_ids)
|
|
457
455
|
if run_id in self.run_ids
|
|
458
456
|
}
|
|
@@ -466,7 +464,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
466
464
|
return False
|
|
467
465
|
|
|
468
466
|
# Check if the status transition is valid
|
|
469
|
-
current_status = self.run_ids[run_id].status
|
|
467
|
+
current_status = self.run_ids[run_id].run.status
|
|
470
468
|
if not is_valid_transition(current_status, new_status):
|
|
471
469
|
log(
|
|
472
470
|
ERROR,
|
|
@@ -489,12 +487,12 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
489
487
|
# Update the status
|
|
490
488
|
run_record = self.run_ids[run_id]
|
|
491
489
|
if new_status.status == Status.STARTING:
|
|
492
|
-
run_record.starting_at = now().isoformat()
|
|
490
|
+
run_record.run.starting_at = now().isoformat()
|
|
493
491
|
elif new_status.status == Status.RUNNING:
|
|
494
|
-
run_record.running_at = now().isoformat()
|
|
492
|
+
run_record.run.running_at = now().isoformat()
|
|
495
493
|
elif new_status.status == Status.FINISHED:
|
|
496
|
-
run_record.finished_at = now().isoformat()
|
|
497
|
-
run_record.status = new_status
|
|
494
|
+
run_record.run.finished_at = now().isoformat()
|
|
495
|
+
run_record.run.status = new_status
|
|
498
496
|
return True
|
|
499
497
|
|
|
500
498
|
def get_pending_run_id(self) -> Optional[int]:
|
|
@@ -504,7 +502,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
504
502
|
# Loop through all registered runs
|
|
505
503
|
for run_id, run_rec in self.run_ids.items():
|
|
506
504
|
# Break once a pending run is found
|
|
507
|
-
if run_rec.status.status == Status.PENDING:
|
|
505
|
+
if run_rec.run.status.status == Status.PENDING:
|
|
508
506
|
pending_run_id = run_id
|
|
509
507
|
break
|
|
510
508
|
|
|
@@ -922,6 +922,15 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
|
922
922
|
fab_version=row["fab_version"],
|
|
923
923
|
fab_hash=row["fab_hash"],
|
|
924
924
|
override_config=json.loads(row["override_config"]),
|
|
925
|
+
pending_at=row["pending_at"],
|
|
926
|
+
starting_at=row["starting_at"],
|
|
927
|
+
running_at=row["running_at"],
|
|
928
|
+
finished_at=row["finished_at"],
|
|
929
|
+
status=RunStatus(
|
|
930
|
+
status=determine_run_status(row),
|
|
931
|
+
sub_status=row["sub_status"],
|
|
932
|
+
details=row["details"],
|
|
933
|
+
),
|
|
925
934
|
)
|
|
926
935
|
log(ERROR, "`run_id` does not exist.")
|
|
927
936
|
return None
|
|
@@ -123,13 +123,8 @@ def run_simulation_from_cli() -> None:
|
|
|
123
123
|
fused_config = get_fused_config_from_dir(app_path, override_config)
|
|
124
124
|
|
|
125
125
|
# Create run
|
|
126
|
-
run = Run(
|
|
127
|
-
|
|
128
|
-
fab_id="",
|
|
129
|
-
fab_version="",
|
|
130
|
-
fab_hash="",
|
|
131
|
-
override_config=override_config,
|
|
132
|
-
)
|
|
126
|
+
run = Run.create_empty(run_id)
|
|
127
|
+
run.override_config = override_config
|
|
133
128
|
|
|
134
129
|
_run_simulation(
|
|
135
130
|
server_app_attr=server_app_attr,
|
|
@@ -333,14 +328,10 @@ def _main_loop(
|
|
|
333
328
|
try:
|
|
334
329
|
# Register run
|
|
335
330
|
log(DEBUG, "Pre-registering run with id %s", run.run_id)
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
starting_at=now().isoformat(),
|
|
341
|
-
running_at=now().isoformat(),
|
|
342
|
-
finished_at="",
|
|
343
|
-
)
|
|
331
|
+
run.status = RunStatus(Status.RUNNING, "", "")
|
|
332
|
+
run.starting_at = now().isoformat()
|
|
333
|
+
run.running_at = run.starting_at
|
|
334
|
+
state_factory.state().run_ids[run.run_id] = RunRecord(run=run) # type: ignore
|
|
344
335
|
|
|
345
336
|
if server_app_run_config is None:
|
|
346
337
|
server_app_run_config = {}
|
|
@@ -457,9 +448,7 @@ def _run_simulation(
|
|
|
457
448
|
# If no `Run` object is set, create one
|
|
458
449
|
if run is None:
|
|
459
450
|
run_id = generate_rand_int_from_bytes(RUN_ID_NUM_BYTES)
|
|
460
|
-
run = Run(
|
|
461
|
-
run_id=run_id, fab_id="", fab_version="", fab_hash="", override_config={}
|
|
462
|
-
)
|
|
451
|
+
run = Run.create_empty(run_id=run_id)
|
|
463
452
|
|
|
464
453
|
args = (
|
|
465
454
|
num_supernodes,
|
flwr/superexec/exec_servicer.py
CHANGED
|
@@ -22,18 +22,25 @@ from typing import Any
|
|
|
22
22
|
|
|
23
23
|
import grpc
|
|
24
24
|
|
|
25
|
+
from flwr.common import now
|
|
25
26
|
from flwr.common.constant import LOG_STREAM_INTERVAL, Status
|
|
26
27
|
from flwr.common.logger import log
|
|
27
|
-
from flwr.common.serde import
|
|
28
|
+
from flwr.common.serde import (
|
|
29
|
+
configs_record_from_proto,
|
|
30
|
+
run_to_proto,
|
|
31
|
+
user_config_from_proto,
|
|
32
|
+
)
|
|
28
33
|
from flwr.proto import exec_pb2_grpc # pylint: disable=E0611
|
|
29
34
|
from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
35
|
+
ListRunsRequest,
|
|
36
|
+
ListRunsResponse,
|
|
30
37
|
StartRunRequest,
|
|
31
38
|
StartRunResponse,
|
|
32
39
|
StreamLogsRequest,
|
|
33
40
|
StreamLogsResponse,
|
|
34
41
|
)
|
|
35
42
|
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
36
|
-
from flwr.server.superlink.linkstate import LinkStateFactory
|
|
43
|
+
from flwr.server.superlink.linkstate import LinkState, LinkStateFactory
|
|
37
44
|
|
|
38
45
|
from .executor import Executor
|
|
39
46
|
|
|
@@ -105,3 +112,25 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
|
|
|
105
112
|
context.cancel()
|
|
106
113
|
|
|
107
114
|
time.sleep(LOG_STREAM_INTERVAL) # Sleep briefly to avoid busy waiting
|
|
115
|
+
|
|
116
|
+
def ListRuns(
|
|
117
|
+
self, request: ListRunsRequest, context: grpc.ServicerContext
|
|
118
|
+
) -> ListRunsResponse:
|
|
119
|
+
"""Handle `flwr ls` command."""
|
|
120
|
+
log(INFO, "ExecServicer.List")
|
|
121
|
+
state = self.linkstate_factory.state()
|
|
122
|
+
|
|
123
|
+
# Handle `flwr ls --runs`
|
|
124
|
+
if not request.HasField("run_id"):
|
|
125
|
+
return _create_list_runs_response(state.get_run_ids(), state)
|
|
126
|
+
# Handle `flwr ls --run-id <run_id>`
|
|
127
|
+
return _create_list_runs_response({request.run_id}, state)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _create_list_runs_response(run_ids: set[int], state: LinkState) -> ListRunsResponse:
|
|
131
|
+
"""Create response for `flwr ls --runs` and `flwr ls --run-id <run_id>`."""
|
|
132
|
+
run_dict = {run_id: state.get_run(run_id) for run_id in run_ids}
|
|
133
|
+
return ListRunsResponse(
|
|
134
|
+
run_dict={run_id: run_to_proto(run) for run_id, run in run_dict.items() if run},
|
|
135
|
+
now=now().isoformat(),
|
|
136
|
+
)
|