flwr-nightly 1.19.0.dev20250602__py3-none-any.whl → 1.19.0.dev20250603__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.
- flwr/client/grpc_rere_client/connection.py +9 -18
- flwr/common/inflatable.py +8 -2
- flwr/common/inflatable_grpc_utils.py +3 -2
- flwr/common/record/metricrecord.py +1 -1
- flwr/common/retry_invoker.py +5 -1
- flwr/proto/message_pb2.py +2 -2
- flwr/proto/message_pb2.pyi +7 -1
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +62 -5
- flwr/server/superlink/serverappio/serverappio_servicer.py +58 -3
- flwr/supernode/cli/flower_supernode.py +1 -2
- flwr/supernode/start_client_internal.py +23 -16
- {flwr_nightly-1.19.0.dev20250602.dist-info → flwr_nightly-1.19.0.dev20250603.dist-info}/METADATA +1 -1
- {flwr_nightly-1.19.0.dev20250602.dist-info → flwr_nightly-1.19.0.dev20250603.dist-info}/RECORD +15 -15
- {flwr_nightly-1.19.0.dev20250602.dist-info → flwr_nightly-1.19.0.dev20250603.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.19.0.dev20250602.dist-info → flwr_nightly-1.19.0.dev20250603.dist-info}/entry_points.txt +0 -0
@@ -33,7 +33,7 @@ from flwr.common.grpc import create_channel, on_channel_state_change
|
|
33
33
|
from flwr.common.heartbeat import HeartbeatSender
|
34
34
|
from flwr.common.logger import log
|
35
35
|
from flwr.common.message import Message
|
36
|
-
from flwr.common.retry_invoker import RetryInvoker
|
36
|
+
from flwr.common.retry_invoker import RetryInvoker, _wrap_stub
|
37
37
|
from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
|
38
38
|
generate_key_pairs,
|
39
39
|
)
|
@@ -159,6 +159,8 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
159
159
|
# If the status code is PERMISSION_DENIED, additionally raise RunNotRunningException
|
160
160
|
retry_invoker.should_giveup = _should_giveup_fn
|
161
161
|
|
162
|
+
# Wrap stub
|
163
|
+
_wrap_stub(stub, retry_invoker)
|
162
164
|
###########################################################################
|
163
165
|
# send_node_heartbeat/create_node/delete_node/receive/send/get_run functions
|
164
166
|
###########################################################################
|
@@ -203,10 +205,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
203
205
|
create_node_request = CreateNodeRequest(
|
204
206
|
heartbeat_interval=HEARTBEAT_DEFAULT_INTERVAL
|
205
207
|
)
|
206
|
-
create_node_response =
|
207
|
-
stub.CreateNode,
|
208
|
-
request=create_node_request,
|
209
|
-
)
|
208
|
+
create_node_response = stub.CreateNode(request=create_node_request)
|
210
209
|
|
211
210
|
# Remember the node and start the heartbeat sender
|
212
211
|
nonlocal node
|
@@ -227,7 +226,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
227
226
|
|
228
227
|
# Call FleetAPI
|
229
228
|
delete_node_request = DeleteNodeRequest(node=node)
|
230
|
-
|
229
|
+
stub.DeleteNode(request=delete_node_request)
|
231
230
|
|
232
231
|
# Cleanup
|
233
232
|
node = None
|
@@ -241,9 +240,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
241
240
|
|
242
241
|
# Request instructions (message) from server
|
243
242
|
request = PullMessagesRequest(node=node)
|
244
|
-
response: PullMessagesResponse =
|
245
|
-
stub.PullMessages, request=request
|
246
|
-
)
|
243
|
+
response: PullMessagesResponse = stub.PullMessages(request=request)
|
247
244
|
|
248
245
|
# Get the current Messages
|
249
246
|
message_proto = (
|
@@ -289,7 +286,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
289
286
|
# Serialize Message
|
290
287
|
message_proto = message_to_proto(message=message)
|
291
288
|
request = PushMessagesRequest(node=node, messages_list=[message_proto])
|
292
|
-
_ =
|
289
|
+
_ = stub.PushMessages(request)
|
293
290
|
|
294
291
|
# Cleanup
|
295
292
|
metadata = None
|
@@ -297,10 +294,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
297
294
|
def get_run(run_id: int) -> Run:
|
298
295
|
# Call FleetAPI
|
299
296
|
get_run_request = GetRunRequest(node=node, run_id=run_id)
|
300
|
-
get_run_response: GetRunResponse =
|
301
|
-
stub.GetRun,
|
302
|
-
request=get_run_request,
|
303
|
-
)
|
297
|
+
get_run_response: GetRunResponse = stub.GetRun(request=get_run_request)
|
304
298
|
|
305
299
|
# Return fab_id and fab_version
|
306
300
|
return run_from_proto(get_run_response.run)
|
@@ -308,10 +302,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
308
302
|
def get_fab(fab_hash: str, run_id: int) -> Fab:
|
309
303
|
# Call FleetAPI
|
310
304
|
get_fab_request = GetFabRequest(node=node, hash_str=fab_hash, run_id=run_id)
|
311
|
-
get_fab_response: GetFabResponse =
|
312
|
-
stub.GetFab,
|
313
|
-
request=get_fab_request,
|
314
|
-
)
|
305
|
+
get_fab_response: GetFabResponse = stub.GetFab(request=get_fab_request)
|
315
306
|
|
316
307
|
return Fab(get_fab_response.fab.hash_str, get_fab_response.fab.content)
|
317
308
|
|
flwr/common/inflatable.py
CHANGED
@@ -18,9 +18,11 @@
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
20
|
import hashlib
|
21
|
+
from logging import ERROR
|
21
22
|
from typing import TypeVar, cast
|
22
23
|
|
23
24
|
from .constant import HEAD_BODY_DIVIDER, HEAD_VALUE_DIVIDER
|
25
|
+
from .logger import log
|
24
26
|
|
25
27
|
|
26
28
|
class InflatableObject:
|
@@ -163,8 +165,12 @@ def get_object_body_len_from_object_content(object_content: bytes) -> int:
|
|
163
165
|
|
164
166
|
def check_body_len_consistency(object_content: bytes) -> bool:
|
165
167
|
"""Check that the object body is of length as specified in the head."""
|
166
|
-
|
167
|
-
|
168
|
+
try:
|
169
|
+
body_len = get_object_body_len_from_object_content(object_content)
|
170
|
+
return body_len == len(_get_object_body(object_content))
|
171
|
+
except ValueError:
|
172
|
+
log(ERROR, "Object content does match the expected format.")
|
173
|
+
return False
|
168
174
|
|
169
175
|
|
170
176
|
def get_object_head_values_from_object_content(
|
@@ -17,6 +17,7 @@
|
|
17
17
|
|
18
18
|
from typing import Optional, Union
|
19
19
|
|
20
|
+
from flwr.client.grpc_rere_client.grpc_adapter import GrpcAdapter
|
20
21
|
from flwr.proto.fleet_pb2_grpc import FleetStub # pylint: disable=E0611
|
21
22
|
from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
22
23
|
PullObjectRequest,
|
@@ -48,7 +49,7 @@ inflatable_class_registry: dict[str, type[InflatableObject]] = {
|
|
48
49
|
|
49
50
|
def push_object_to_servicer(
|
50
51
|
obj: InflatableObject,
|
51
|
-
stub: Union[FleetStub, ServerAppIoStub],
|
52
|
+
stub: Union[FleetStub, ServerAppIoStub, GrpcAdapter],
|
52
53
|
node: Node,
|
53
54
|
run_id: int,
|
54
55
|
object_ids_to_push: Optional[set[str]] = None,
|
@@ -87,7 +88,7 @@ def push_object_to_servicer(
|
|
87
88
|
|
88
89
|
def pull_object_from_servicer(
|
89
90
|
object_id: str,
|
90
|
-
stub: Union[FleetStub, ServerAppIoStub],
|
91
|
+
stub: Union[FleetStub, ServerAppIoStub, GrpcAdapter],
|
91
92
|
node: Node,
|
92
93
|
run_id: int,
|
93
94
|
) -> InflatableObject:
|
@@ -180,7 +180,7 @@ class MetricRecord(TypedDict[str, MetricRecordValues], InflatableObject):
|
|
180
180
|
MetricRecord
|
181
181
|
The inflated MetricRecord.
|
182
182
|
"""
|
183
|
-
if children
|
183
|
+
if children:
|
184
184
|
raise ValueError("`MetricRecord` objects do not have children.")
|
185
185
|
|
186
186
|
obj_body = get_object_body(object_content, cls)
|
flwr/common/retry_invoker.py
CHANGED
@@ -25,10 +25,12 @@ from typing import Any, Callable, Optional, Union, cast
|
|
25
25
|
|
26
26
|
import grpc
|
27
27
|
|
28
|
+
from flwr.client.grpc_rere_client.grpc_adapter import GrpcAdapter
|
28
29
|
from flwr.common.constant import MAX_RETRY_DELAY
|
29
30
|
from flwr.common.logger import log
|
30
31
|
from flwr.common.typing import RunNotRunningException
|
31
32
|
from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
|
33
|
+
from flwr.proto.fleet_pb2_grpc import FleetStub
|
32
34
|
from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
|
33
35
|
from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
|
34
36
|
|
@@ -366,7 +368,9 @@ def _make_simple_grpc_retry_invoker() -> RetryInvoker:
|
|
366
368
|
|
367
369
|
|
368
370
|
def _wrap_stub(
|
369
|
-
stub: Union[
|
371
|
+
stub: Union[
|
372
|
+
ServerAppIoStub, ClientAppIoStub, SimulationIoStub, FleetStub, GrpcAdapter
|
373
|
+
],
|
370
374
|
retry_invoker: RetryInvoker,
|
371
375
|
) -> None:
|
372
376
|
"""Wrap a gRPC stub with a retry invoker."""
|
flwr/proto/message_pb2.py
CHANGED
@@ -18,7 +18,7 @@ from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
|
|
18
18
|
from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
|
19
19
|
|
20
20
|
|
21
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/message.proto\x12\nflwr.proto\x1a\x16\x66lwr/proto/error.proto\x1a\x1b\x66lwr/proto/recorddict.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x15\x66lwr/proto/node.proto\"|\n\x07Message\x12&\n\x08metadata\x18\x01 \x01(\x0b\x32\x14.flwr.proto.Metadata\x12\'\n\x07\x63ontent\x18\x02 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12 \n\x05\x65rror\x18\x03 \x01(\x0b\x32\x11.flwr.proto.Error\"\xd0\x02\n\x07\x43ontext\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x0f\n\x07node_id\x18\x02 \x01(\x04\x12\x38\n\x0bnode_config\x18\x03 \x03(\x0b\x32#.flwr.proto.Context.NodeConfigEntry\x12%\n\x05state\x18\x04 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12\x36\n\nrun_config\x18\x05 \x03(\x0b\x32\".flwr.proto.Context.RunConfigEntry\x1a\x45\n\x0fNodeConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1a\x44\n\x0eRunConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\xbe\x01\n\x08Metadata\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x12\n\nmessage_id\x18\x02 \x01(\t\x12\x13\n\x0bsrc_node_id\x18\x03 \x01(\x04\x12\x13\n\x0b\x64st_node_id\x18\x04 \x01(\x04\x12\x1b\n\x13reply_to_message_id\x18\x05 \x01(\t\x12\x10\n\x08group_id\x18\x06 \x01(\t\x12\x0b\n\x03ttl\x18\x07 \x01(\x01\x12\x14\n\x0cmessage_type\x18\x08 \x01(\t\x12\x12\n\ncreated_at\x18\t \x01(\x01\"\x1f\n\tObjectIDs\x12\x12\n\nobject_ids\x18\x01 \x03(\t\"n\n\x11PushObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\x12\x11\n\tobject_id\x18\x03 \x01(\t\x12\x16\n\x0eobject_content\x18\x04 \x01(\x0c\"$\n\x12PushObjectResponse\x12\x0e\n\x06stored\x18\x01 \x01(\x08\"V\n\x11PullObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\x12\x11\n\tobject_id\x18\x03 \x01(\t\"
|
21
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/message.proto\x12\nflwr.proto\x1a\x16\x66lwr/proto/error.proto\x1a\x1b\x66lwr/proto/recorddict.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x15\x66lwr/proto/node.proto\"|\n\x07Message\x12&\n\x08metadata\x18\x01 \x01(\x0b\x32\x14.flwr.proto.Metadata\x12\'\n\x07\x63ontent\x18\x02 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12 \n\x05\x65rror\x18\x03 \x01(\x0b\x32\x11.flwr.proto.Error\"\xd0\x02\n\x07\x43ontext\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x0f\n\x07node_id\x18\x02 \x01(\x04\x12\x38\n\x0bnode_config\x18\x03 \x03(\x0b\x32#.flwr.proto.Context.NodeConfigEntry\x12%\n\x05state\x18\x04 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12\x36\n\nrun_config\x18\x05 \x03(\x0b\x32\".flwr.proto.Context.RunConfigEntry\x1a\x45\n\x0fNodeConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1a\x44\n\x0eRunConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\xbe\x01\n\x08Metadata\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x12\n\nmessage_id\x18\x02 \x01(\t\x12\x13\n\x0bsrc_node_id\x18\x03 \x01(\x04\x12\x13\n\x0b\x64st_node_id\x18\x04 \x01(\x04\x12\x1b\n\x13reply_to_message_id\x18\x05 \x01(\t\x12\x10\n\x08group_id\x18\x06 \x01(\t\x12\x0b\n\x03ttl\x18\x07 \x01(\x01\x12\x14\n\x0cmessage_type\x18\x08 \x01(\t\x12\x12\n\ncreated_at\x18\t \x01(\x01\"\x1f\n\tObjectIDs\x12\x12\n\nobject_ids\x18\x01 \x03(\t\"n\n\x11PushObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\x12\x11\n\tobject_id\x18\x03 \x01(\t\x12\x16\n\x0eobject_content\x18\x04 \x01(\x0c\"$\n\x12PushObjectResponse\x12\x0e\n\x06stored\x18\x01 \x01(\x08\"V\n\x11PullObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\x12\x11\n\tobject_id\x18\x03 \x01(\t\"\\\n\x12PullObjectResponse\x12\x14\n\x0cobject_found\x18\x01 \x01(\x08\x12\x18\n\x10object_available\x18\x02 \x01(\x08\x12\x16\n\x0eobject_content\x18\x03 \x01(\x0c\x62\x06proto3')
|
22
22
|
|
23
23
|
_globals = globals()
|
24
24
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
@@ -48,5 +48,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
48
48
|
_globals['_PULLOBJECTREQUEST']._serialized_start=985
|
49
49
|
_globals['_PULLOBJECTREQUEST']._serialized_end=1071
|
50
50
|
_globals['_PULLOBJECTRESPONSE']._serialized_start=1073
|
51
|
-
_globals['_PULLOBJECTRESPONSE']._serialized_end=
|
51
|
+
_globals['_PULLOBJECTRESPONSE']._serialized_end=1165
|
52
52
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/message_pb2.pyi
CHANGED
@@ -196,11 +196,17 @@ global___PullObjectRequest = PullObjectRequest
|
|
196
196
|
|
197
197
|
class PullObjectResponse(google.protobuf.message.Message):
|
198
198
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
199
|
+
OBJECT_FOUND_FIELD_NUMBER: builtins.int
|
200
|
+
OBJECT_AVAILABLE_FIELD_NUMBER: builtins.int
|
199
201
|
OBJECT_CONTENT_FIELD_NUMBER: builtins.int
|
202
|
+
object_found: builtins.bool
|
203
|
+
object_available: builtins.bool
|
200
204
|
object_content: builtins.bytes
|
201
205
|
def __init__(self,
|
202
206
|
*,
|
207
|
+
object_found: builtins.bool = ...,
|
208
|
+
object_available: builtins.bool = ...,
|
203
209
|
object_content: builtins.bytes = ...,
|
204
210
|
) -> None: ...
|
205
|
-
def ClearField(self, field_name: typing_extensions.Literal["object_content",b"object_content"]) -> None: ...
|
211
|
+
def ClearField(self, field_name: typing_extensions.Literal["object_available",b"object_available","object_content",b"object_content","object_found",b"object_found"]) -> None: ...
|
206
212
|
global___PullObjectResponse = PullObjectResponse
|
@@ -15,11 +15,12 @@
|
|
15
15
|
"""Fleet API gRPC request-response servicer."""
|
16
16
|
|
17
17
|
|
18
|
-
from logging import DEBUG, INFO
|
18
|
+
from logging import DEBUG, ERROR, INFO
|
19
19
|
|
20
20
|
import grpc
|
21
21
|
from google.protobuf.json_format import MessageToDict
|
22
22
|
|
23
|
+
from flwr.common.constant import Status
|
23
24
|
from flwr.common.inflatable import check_body_len_consistency
|
24
25
|
from flwr.common.logger import log
|
25
26
|
from flwr.common.typing import InvalidRunStatusException
|
@@ -49,8 +50,9 @@ from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=
|
|
49
50
|
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
50
51
|
from flwr.server.superlink.fleet.message_handler import message_handler
|
51
52
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
52
|
-
from flwr.server.superlink.utils import abort_grpc_context
|
53
|
+
from flwr.server.superlink.utils import abort_grpc_context, check_abort
|
53
54
|
from flwr.supercore.object_store import ObjectStoreFactory
|
55
|
+
from flwr.supercore.object_store.object_store import NoObjectInStoreError
|
54
56
|
|
55
57
|
|
56
58
|
class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
@@ -183,11 +185,39 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
|
183
185
|
request.object_id,
|
184
186
|
)
|
185
187
|
|
188
|
+
state = self.state_factory.state()
|
189
|
+
|
190
|
+
# Abort if the run is not running
|
191
|
+
abort_msg = check_abort(
|
192
|
+
request.run_id,
|
193
|
+
[Status.PENDING, Status.STARTING, Status.FINISHED],
|
194
|
+
state,
|
195
|
+
)
|
196
|
+
if abort_msg:
|
197
|
+
abort_grpc_context(abort_msg, context)
|
198
|
+
|
199
|
+
if request.node.node_id not in state.get_nodes(run_id=request.run_id):
|
200
|
+
# Cancel insertion in ObjectStore
|
201
|
+
context.abort(grpc.StatusCode.FAILED_PRECONDITION, "Unexpected node ID.")
|
202
|
+
|
186
203
|
if not check_body_len_consistency(request.object_content):
|
187
204
|
# Cancel insertion in ObjectStore
|
188
|
-
context.abort(
|
205
|
+
context.abort(
|
206
|
+
grpc.StatusCode.FAILED_PRECONDITION, "Unexpected object length"
|
207
|
+
)
|
208
|
+
|
209
|
+
# Init store
|
210
|
+
store = self.objectstore_factory.store()
|
211
|
+
|
212
|
+
# Insert in store
|
213
|
+
stored = False
|
214
|
+
try:
|
215
|
+
store.put(request.object_id, request.object_content)
|
216
|
+
stored = True
|
217
|
+
except (NoObjectInStoreError, ValueError) as e:
|
218
|
+
log(ERROR, str(e))
|
189
219
|
|
190
|
-
return PushObjectResponse()
|
220
|
+
return PushObjectResponse(stored=stored)
|
191
221
|
|
192
222
|
def PullObject(
|
193
223
|
self, request: PullObjectRequest, context: grpc.ServicerContext
|
@@ -199,4 +229,31 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
|
199
229
|
request.object_id,
|
200
230
|
)
|
201
231
|
|
202
|
-
|
232
|
+
state = self.state_factory.state()
|
233
|
+
|
234
|
+
# Abort if the run is not running
|
235
|
+
abort_msg = check_abort(
|
236
|
+
request.run_id,
|
237
|
+
[Status.PENDING, Status.STARTING, Status.FINISHED],
|
238
|
+
state,
|
239
|
+
)
|
240
|
+
if abort_msg:
|
241
|
+
abort_grpc_context(abort_msg, context)
|
242
|
+
|
243
|
+
if request.node.node_id not in state.get_nodes(run_id=request.run_id):
|
244
|
+
# Cancel insertion in ObjectStore
|
245
|
+
context.abort(grpc.StatusCode.FAILED_PRECONDITION, "Unexpected node ID.")
|
246
|
+
|
247
|
+
# Init store
|
248
|
+
store = self.objectstore_factory.store()
|
249
|
+
|
250
|
+
# Fetch from store
|
251
|
+
content = store.get(request.object_id)
|
252
|
+
if content is not None:
|
253
|
+
object_available = content != b""
|
254
|
+
return PullObjectResponse(
|
255
|
+
object_found=True,
|
256
|
+
object_available=object_available,
|
257
|
+
object_content=content,
|
258
|
+
)
|
259
|
+
return PullObjectResponse(object_found=False, object_available=False)
|
@@ -409,11 +409,39 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
409
409
|
"""Push an object to the ObjectStore."""
|
410
410
|
log(DEBUG, "ServerAppIoServicer.PushObject")
|
411
411
|
|
412
|
+
# Init state
|
413
|
+
state: LinkState = self.state_factory.state()
|
414
|
+
|
415
|
+
# Abort if the run is not running
|
416
|
+
abort_if(
|
417
|
+
request.run_id,
|
418
|
+
[Status.PENDING, Status.STARTING, Status.FINISHED],
|
419
|
+
state,
|
420
|
+
context,
|
421
|
+
)
|
422
|
+
|
423
|
+
if request.node.node_id != SUPERLINK_NODE_ID:
|
424
|
+
# Cancel insertion in ObjectStore
|
425
|
+
context.abort(grpc.StatusCode.FAILED_PRECONDITION, "Unexpected node ID.")
|
426
|
+
|
412
427
|
if not check_body_len_consistency(request.object_content):
|
413
428
|
# Cancel insertion in ObjectStore
|
414
|
-
context.abort(
|
429
|
+
context.abort(
|
430
|
+
grpc.StatusCode.FAILED_PRECONDITION, "Unexpected object length."
|
431
|
+
)
|
432
|
+
|
433
|
+
# Init store
|
434
|
+
store = self.objectstore_factory.store()
|
435
|
+
|
436
|
+
# Insert in store
|
437
|
+
stored = False
|
438
|
+
try:
|
439
|
+
store.put(request.object_id, request.object_content)
|
440
|
+
stored = True
|
441
|
+
except (NoObjectInStoreError, ValueError) as e:
|
442
|
+
log(ERROR, str(e))
|
415
443
|
|
416
|
-
return PushObjectResponse()
|
444
|
+
return PushObjectResponse(stored=stored)
|
417
445
|
|
418
446
|
def PullObject(
|
419
447
|
self, request: PullObjectRequest, context: grpc.ServicerContext
|
@@ -421,7 +449,34 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
421
449
|
"""Pull an object from the ObjectStore."""
|
422
450
|
log(DEBUG, "ServerAppIoServicer.PullObject")
|
423
451
|
|
424
|
-
|
452
|
+
# Init state
|
453
|
+
state: LinkState = self.state_factory.state()
|
454
|
+
|
455
|
+
# Abort if the run is not running
|
456
|
+
abort_if(
|
457
|
+
request.run_id,
|
458
|
+
[Status.PENDING, Status.STARTING, Status.FINISHED],
|
459
|
+
state,
|
460
|
+
context,
|
461
|
+
)
|
462
|
+
|
463
|
+
if request.node.node_id != SUPERLINK_NODE_ID:
|
464
|
+
# Cancel insertion in ObjectStore
|
465
|
+
context.abort(grpc.StatusCode.FAILED_PRECONDITION, "Unexpected node ID.")
|
466
|
+
|
467
|
+
# Init store
|
468
|
+
store = self.objectstore_factory.store()
|
469
|
+
|
470
|
+
# Fetch from store
|
471
|
+
content = store.get(request.object_id)
|
472
|
+
if content is not None:
|
473
|
+
object_available = content != b""
|
474
|
+
return PullObjectResponse(
|
475
|
+
object_found=True,
|
476
|
+
object_available=object_available,
|
477
|
+
object_content=content,
|
478
|
+
)
|
479
|
+
return PullObjectResponse(object_found=False, object_available=False)
|
425
480
|
|
426
481
|
|
427
482
|
def _raise_if(validation_error: bool, request_name: str, detail: str) -> None:
|
@@ -42,8 +42,7 @@ from flwr.common.constant import (
|
|
42
42
|
from flwr.common.exit import ExitCode, flwr_exit
|
43
43
|
from flwr.common.exit_handlers import register_exit_handlers
|
44
44
|
from flwr.common.logger import log
|
45
|
-
|
46
|
-
from ..start_client_internal import start_client_internal
|
45
|
+
from flwr.supernode.start_client_internal import start_client_internal
|
47
46
|
|
48
47
|
|
49
48
|
def flower_supernode() -> None:
|
@@ -17,7 +17,6 @@
|
|
17
17
|
|
18
18
|
import multiprocessing
|
19
19
|
import os
|
20
|
-
import sys
|
21
20
|
import threading
|
22
21
|
import time
|
23
22
|
from collections.abc import Iterator
|
@@ -57,8 +56,8 @@ from flwr.common.logger import log
|
|
57
56
|
from flwr.common.retry_invoker import RetryInvoker, RetryState, exponential
|
58
57
|
from flwr.common.typing import Fab, Run, RunNotRunningException, UserConfig
|
59
58
|
from flwr.proto.clientappio_pb2_grpc import add_ClientAppIoServicer_to_server
|
60
|
-
from flwr.supernode.cli.flwr_clientapp import flwr_clientapp
|
61
59
|
from flwr.supernode.nodestate import NodeStateFactory
|
60
|
+
from flwr.supernode.runtime.run_clientapp import run_clientapp
|
62
61
|
from flwr.supernode.servicer.clientappio import ClientAppInputs, ClientAppIoServicer
|
63
62
|
|
64
63
|
|
@@ -259,18 +258,14 @@ def start_client_internal(
|
|
259
258
|
else clientappio_api_address
|
260
259
|
)
|
261
260
|
# Start ClientApp subprocess
|
262
|
-
command = [
|
263
|
-
"flwr-clientapp",
|
264
|
-
"--clientappio-api-address",
|
265
|
-
io_address,
|
266
|
-
"--token",
|
267
|
-
str(token),
|
268
|
-
]
|
269
|
-
command.append("--insecure")
|
270
|
-
|
271
261
|
proc = mp_spawn_context.Process(
|
272
262
|
target=_run_flwr_clientapp,
|
273
|
-
|
263
|
+
kwargs={
|
264
|
+
"main_pid": os.getpid(),
|
265
|
+
"clientappio_api_address": io_address,
|
266
|
+
"run_once": True,
|
267
|
+
"token": token,
|
268
|
+
},
|
274
269
|
daemon=True,
|
275
270
|
)
|
276
271
|
proc.start()
|
@@ -421,7 +416,14 @@ def _make_fleet_connection_retry_invoker(
|
|
421
416
|
)
|
422
417
|
|
423
418
|
|
424
|
-
def _run_flwr_clientapp(
|
419
|
+
def _run_flwr_clientapp( # pylint: disable=R0917
|
420
|
+
main_pid: int,
|
421
|
+
clientappio_api_address: str,
|
422
|
+
run_once: bool,
|
423
|
+
token: Optional[int] = None,
|
424
|
+
flwr_dir: Optional[str] = None,
|
425
|
+
certificates: Optional[bytes] = None,
|
426
|
+
) -> None:
|
425
427
|
# Monitor the main process in case of SIGKILL
|
426
428
|
def main_process_monitor() -> None:
|
427
429
|
while True:
|
@@ -431,9 +433,14 @@ def _run_flwr_clientapp(args: list[str], main_pid: int) -> None:
|
|
431
433
|
|
432
434
|
threading.Thread(target=main_process_monitor, daemon=True).start()
|
433
435
|
|
434
|
-
# Run
|
435
|
-
|
436
|
-
|
436
|
+
# Run flwr-clientapp
|
437
|
+
run_clientapp(
|
438
|
+
clientappio_api_address=clientappio_api_address,
|
439
|
+
run_once=run_once,
|
440
|
+
token=token,
|
441
|
+
flwr_dir=flwr_dir,
|
442
|
+
certificates=certificates,
|
443
|
+
)
|
437
444
|
|
438
445
|
|
439
446
|
def run_clientappio_api_grpc(
|
{flwr_nightly-1.19.0.dev20250602.dist-info → flwr_nightly-1.19.0.dev20250603.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.19.0.
|
3
|
+
Version: 1.19.0.dev20250603
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
5
5
|
License: Apache-2.0
|
6
6
|
Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
|
{flwr_nightly-1.19.0.dev20250602.dist-info → flwr_nightly-1.19.0.dev20250603.dist-info}/RECORD
RENAMED
@@ -84,7 +84,7 @@ flwr/client/grpc_adapter_client/__init__.py,sha256=RQWP5mFPROLHKgombiRvPXVWSoVrQ
|
|
84
84
|
flwr/client/grpc_adapter_client/connection.py,sha256=aj5tTYyE8z2hQLXPPydsJiz8gBDIWLUhfWvqYkAL1L4,3966
|
85
85
|
flwr/client/grpc_rere_client/__init__.py,sha256=i7iS0Lt8B7q0E2L72e4F_YrKm6ClRKnd71PNA6PW2O0,752
|
86
86
|
flwr/client/grpc_rere_client/client_interceptor.py,sha256=zFaVHw6AxeNO-7eCKKb-RxrPa7zbM5Z-2-1Efc4adQY,2451
|
87
|
-
flwr/client/grpc_rere_client/connection.py,sha256=
|
87
|
+
flwr/client/grpc_rere_client/connection.py,sha256=QEUjpXdWGVn_kaFv6Hv2WmJRpcggjMzR7QFpiAa-r6M,11923
|
88
88
|
flwr/client/grpc_rere_client/grpc_adapter.py,sha256=JvMZ7vCFTaTEo6AzKYh3zDmeQAU7VSjdysbC6t3ufWg,6351
|
89
89
|
flwr/client/message_handler/__init__.py,sha256=0lyljDVqre3WljiZbPcwCCf8GiIaSVI_yo_ylEyPwSE,719
|
90
90
|
flwr/client/message_handler/message_handler.py,sha256=X9SXX6et97Lw9_DGD93HKsEBGNjXClcFgc_5aLK0oiU,6541
|
@@ -122,8 +122,8 @@ flwr/common/exit/exit_code.py,sha256=PNEnCrZfOILjfDAFu5m-2YWEJBrk97xglq4zCUlqV7E
|
|
122
122
|
flwr/common/exit_handlers.py,sha256=IaqJ60fXZuu7McaRYnoYKtlbH9t4Yl9goNExKqtmQbs,4304
|
123
123
|
flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
|
124
124
|
flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
|
125
|
-
flwr/common/inflatable.py,sha256=
|
126
|
-
flwr/common/inflatable_grpc_utils.py,sha256=
|
125
|
+
flwr/common/inflatable.py,sha256=9yPsSFOfNM2OIb15JQ6-wY5kblwXiC5zNX-tsp2ZwW0,7017
|
126
|
+
flwr/common/inflatable_grpc_utils.py,sha256=KSrV51jaKsaAA__dROtlTAUC5k_FYJDVcPA0uITWM0s,4161
|
127
127
|
flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
|
128
128
|
flwr/common/message.py,sha256=HfSeqxwXgf90ilbMlM0vrF4cJWqJVx3jJ0gNmTfgdFw,19628
|
129
129
|
flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,9134
|
@@ -134,11 +134,11 @@ flwr/common/record/array.py,sha256=3K01tAf_jedub2r2-vkRshbsjBSiKErAO4KqDgdDaSo,1
|
|
134
134
|
flwr/common/record/arrayrecord.py,sha256=CpoqYXM6Iv4XEc9SryCMYmw-bIvP8ut6xWJzRwYJzdU,18008
|
135
135
|
flwr/common/record/configrecord.py,sha256=G7U0q39kB0Kyi0zMxFmPxcVemL9NgwVS1qjvI4BRQuU,9763
|
136
136
|
flwr/common/record/conversion_utils.py,sha256=wbNCzy7oAqaA3-arhls_EqRZYXRC4YrWIoE-Gy82fJ0,1191
|
137
|
-
flwr/common/record/metricrecord.py,sha256=
|
137
|
+
flwr/common/record/metricrecord.py,sha256=KOyJjJbvFV6IwBPbgm92FZ_0_hXpMHuwfCi1rh5Zddk,8954
|
138
138
|
flwr/common/record/recorddict.py,sha256=p7hBimFpKM1XKUe6OAkR_7pYGzGL_EwUJUvJ8odZEcY,14986
|
139
139
|
flwr/common/record/typeddict.py,sha256=dDKgUThs2BscYUNcgP82KP8-qfAYXYftDrf2LszAC_o,3599
|
140
140
|
flwr/common/recorddict_compat.py,sha256=D5SqXWkqBddn5b6K_5UoH7aZ11UaN3lDTlzvHx3-rqk,14119
|
141
|
-
flwr/common/retry_invoker.py,sha256=
|
141
|
+
flwr/common/retry_invoker.py,sha256=s5IGgRovE19laMetHFePoqIdMBYfz_KdXs-KyfaCrXw,14634
|
142
142
|
flwr/common/secure_aggregation/__init__.py,sha256=MgW6uHGhyFLBAYQqa1Vzs5n2Gc0d4yEw1_NmerFir70,731
|
143
143
|
flwr/common/secure_aggregation/crypto/__init__.py,sha256=5E4q4-Fw0CNz4tLah_QHj7m_rDeM4ucHcFlPWB_Na3Q,738
|
144
144
|
flwr/common/secure_aggregation/crypto/shamir.py,sha256=N8pPa5cEksowNoAqfFm5SP3IuxuVi9GGMa3JOtPniQY,3954
|
@@ -194,8 +194,8 @@ flwr/proto/log_pb2.py,sha256=iKaS3MVn1BS4xHu8uGPFCOi1KWtvVx-H9V4jCUIJghs,1393
|
|
194
194
|
flwr/proto/log_pb2.pyi,sha256=ipuhgo40sAHTcRzCsGI1HwIstr5q0THPNk_cf62YyME,1448
|
195
195
|
flwr/proto/log_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
196
196
|
flwr/proto/log_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
|
197
|
-
flwr/proto/message_pb2.py,sha256=
|
198
|
-
flwr/proto/message_pb2.pyi,sha256=
|
197
|
+
flwr/proto/message_pb2.py,sha256=VoFv02FalR-xegoyqVMC1M_rD02sdWdoAAfFkw00k84,4481
|
198
|
+
flwr/proto/message_pb2.pyi,sha256=FmBgs2PsotAdv-OOCEHp4Dc3e6dSo6-CAB3-pgmva4g,9392
|
199
199
|
flwr/proto/message_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
200
200
|
flwr/proto/message_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
|
201
201
|
flwr/proto/node_pb2.py,sha256=BzZfAWIX7lV62bZr9f7x16lUZcpg-EImxnwxQXgCbYg,1045
|
@@ -284,7 +284,7 @@ flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py,sha256=KouR9PUcrPmMtoLooF4O
|
|
284
284
|
flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py,sha256=iSf0mbBAlig7G6subQwBSVjcUCgSihONKdZ1RmQPTOk,4887
|
285
285
|
flwr/server/superlink/fleet/grpc_bidi/grpc_server.py,sha256=OsS-6GgCIzMMZDVu5Y-OKjynHVUrpdc_5OrtuB-IbU0,5174
|
286
286
|
flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=ahDJJ1e-lDxBpeBMgPk7YZt2wB38_QltcpOC0gLbpFs,758
|
287
|
-
flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=
|
287
|
+
flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=SsMtj1EeOgumffWtYTQt-ii3JPldszXvP91C3axznq8,9176
|
288
288
|
flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=DrHubsaLgJCwCeeJPYogQTiP0xYqjxwnT9rh7OP7BoU,6984
|
289
289
|
flwr/server/superlink/fleet/message_handler/__init__.py,sha256=fHsRV0KvJ8HtgSA4_YBsEzuhJLjO8p6xx4aCY2oE1p4,731
|
290
290
|
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=P43PapLZJKbZ0Oo0kP_KcO5zSMvO53SakQgPMiR5d1M,6500
|
@@ -303,7 +303,7 @@ flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=sHJPK1w0tP0m2WCXH2F9l
|
|
303
303
|
flwr/server/superlink/linkstate/utils.py,sha256=IeLh7iGRCHU5MEWOl7iriaSE4L__8GWOa2OleXadK5M,15444
|
304
304
|
flwr/server/superlink/serverappio/__init__.py,sha256=Fy4zJuoccZe5mZSEIpOmQvU6YeXFBa1M4eZuXXmJcn8,717
|
305
305
|
flwr/server/superlink/serverappio/serverappio_grpc.py,sha256=6-FUUt0GiLcBPljj8bBrUNeAITUoDQOLzaMihKo52hg,2326
|
306
|
-
flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=
|
306
|
+
flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=qInBXn7xcnNUNIXj_BkjoWfZd96By55gbTsp4onwfDQ,17290
|
307
307
|
flwr/server/superlink/simulation/__init__.py,sha256=Ry8DrNaZCMcQXvUc4FoCN2m3dvUQgWjasfp015o3Ec4,718
|
308
308
|
flwr/server/superlink/simulation/simulationio_grpc.py,sha256=0l0F-UjYEk6W7HZmI28PbJQLFxSi_vBHRkdchgdaSMQ,2224
|
309
309
|
flwr/server/superlink/simulation/simulationio_servicer.py,sha256=aJezU8RSJswcmWm7Eoy0BqsU13jrcfuFwX3ljm-cORM,7719
|
@@ -345,7 +345,7 @@ flwr/superexec/simulation.py,sha256=j6YwUvBN7EQ09ID7MYOCVZ70PGbuyBy8f9bXU0EszEM,
|
|
345
345
|
flwr/superlink/__init__.py,sha256=GNSuJ4-N6Z8wun2iZNlXqENt5beUyzC0Gi_tN396bbM,707
|
346
346
|
flwr/supernode/__init__.py,sha256=KgeCaVvXWrU3rptNR1y0oBp4YtXbAcrnCcJAiOoWkI4,707
|
347
347
|
flwr/supernode/cli/__init__.py,sha256=JuEMr0-s9zv-PEWKuLB9tj1ocNfroSyNJ-oyv7ati9A,887
|
348
|
-
flwr/supernode/cli/flower_supernode.py,sha256=
|
348
|
+
flwr/supernode/cli/flower_supernode.py,sha256=ly2AQhbla2sufDaMsENaEALDEd0a4CS4D0eUrUOkHzY,8778
|
349
349
|
flwr/supernode/cli/flwr_clientapp.py,sha256=ORsNxviXOKGzZdcp5DEiHIuj4RycgB2OaPDaTTJJWz4,2555
|
350
350
|
flwr/supernode/nodestate/__init__.py,sha256=CyLLObbmmVgfRO88UCM0VMait1dL57mUauUDfuSHsbU,976
|
351
351
|
flwr/supernode/nodestate/in_memory_nodestate.py,sha256=4ZiLA45fMi2bJgmfDNLtiv-gVNru95Bi48xBy7xtatA,5212
|
@@ -356,8 +356,8 @@ flwr/supernode/runtime/run_clientapp.py,sha256=sEmrN1F-tV2YAzw06Dk4RM696yyP4xqm2
|
|
356
356
|
flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca8gxdEo,717
|
357
357
|
flwr/supernode/servicer/clientappio/__init__.py,sha256=vJyOjO2FXZ2URbnthmdsgs6948wbYfdq1L1V8Um-Lr8,895
|
358
358
|
flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=LmzkxtNQBn5vVrHc0Bhq2WqaK6-LM2v4kfLBN0PiNNM,8522
|
359
|
-
flwr/supernode/start_client_internal.py,sha256=
|
360
|
-
flwr_nightly-1.19.0.
|
361
|
-
flwr_nightly-1.19.0.
|
362
|
-
flwr_nightly-1.19.0.
|
363
|
-
flwr_nightly-1.19.0.
|
359
|
+
flwr/supernode/start_client_internal.py,sha256=fI44QAbNbrRomwHI83X1sqtPlDcV8oIAWuZ0DxMTCVY,17602
|
360
|
+
flwr_nightly-1.19.0.dev20250603.dist-info/METADATA,sha256=uMka7DkhCI_KfSOFFsib_P7qj7UO05ccr88R1qecUi4,15910
|
361
|
+
flwr_nightly-1.19.0.dev20250603.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
362
|
+
flwr_nightly-1.19.0.dev20250603.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
|
363
|
+
flwr_nightly-1.19.0.dev20250603.dist-info/RECORD,,
|
{flwr_nightly-1.19.0.dev20250602.dist-info → flwr_nightly-1.19.0.dev20250603.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|