flwr-nightly 1.21.0.dev20250819__py3-none-any.whl → 1.21.0.dev20250820__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/common/exit/exit.py +4 -1
- flwr/common/exit/exit_code.py +4 -10
- flwr/server/app.py +33 -21
- flwr/server/grid/grpc_grid.py +1 -0
- flwr/server/grid/inmemory_grid.py +1 -0
- flwr/server/serverapp/app.py +115 -139
- flwr/server/superlink/serverappio/serverappio_grpc.py +1 -1
- flwr/simulation/app.py +127 -154
- flwr/supercore/app_utils.py +0 -31
- flwr/supercore/cli/flower_superexec.py +6 -0
- flwr/superlink/servicer/control/control_grpc.py +4 -9
- flwr/superlink/servicer/control/control_servicer.py +52 -14
- flwr/supernode/start_client_internal.py +1 -1
- {flwr_nightly-1.21.0.dev20250819.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/METADATA +1 -1
- {flwr_nightly-1.21.0.dev20250819.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/RECORD +17 -25
- flwr/superexec/__init__.py +0 -15
- flwr/superexec/deployment.py +0 -20
- flwr/superexec/simulation.py +0 -20
- flwr/superlink/executor/__init__.py +0 -28
- flwr/superlink/executor/app.py +0 -45
- flwr/superlink/executor/deployment.py +0 -188
- flwr/superlink/executor/executor.py +0 -100
- flwr/superlink/executor/simulation.py +0 -126
- {flwr_nightly-1.21.0.dev20250819.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.21.0.dev20250819.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/entry_points.txt +0 -0
flwr/common/exit/exit.py
CHANGED
@@ -22,11 +22,14 @@ from logging import ERROR, INFO
|
|
22
22
|
from typing import Any, NoReturn
|
23
23
|
|
24
24
|
from flwr.common import EventType, event
|
25
|
+
from flwr.common.version import package_version
|
25
26
|
|
26
27
|
from ..logger import log
|
27
28
|
from .exit_code import EXIT_CODE_HELP
|
28
29
|
|
29
|
-
HELP_PAGE_URL =
|
30
|
+
HELP_PAGE_URL = (
|
31
|
+
f"https://flower.ai/docs/framework/v{package_version}/en/ref-exit-codes/"
|
32
|
+
)
|
30
33
|
|
31
34
|
|
32
35
|
def flwr_exit(
|
flwr/common/exit/exit_code.py
CHANGED
@@ -34,18 +34,14 @@ class ExitCode:
|
|
34
34
|
SUPERLINK_LICENSE_URL_INVALID = 103
|
35
35
|
SUPERLINK_INVALID_ARGS = 104
|
36
36
|
|
37
|
-
# ServerApp-specific exit codes (200-299)
|
38
|
-
|
39
37
|
# SuperNode-specific exit codes (300-399)
|
40
38
|
SUPERNODE_REST_ADDRESS_INVALID = 300
|
41
39
|
SUPERNODE_NODE_AUTH_KEYS_REQUIRED = 301
|
42
40
|
SUPERNODE_NODE_AUTH_KEYS_INVALID = 302
|
43
41
|
|
44
|
-
#
|
45
|
-
|
46
|
-
# Simulation-specific exit codes (500-599)
|
42
|
+
# SuperExec-specific exit codes (400-499)
|
47
43
|
|
48
|
-
# Common exit codes (600-)
|
44
|
+
# Common exit codes (600-699)
|
49
45
|
COMMON_ADDRESS_INVALID = 600
|
50
46
|
COMMON_MISSING_EXTRA_REST = 601
|
51
47
|
COMMON_TLS_NOT_SUPPORTED = 602
|
@@ -80,7 +76,6 @@ EXIT_CODE_HELP = {
|
|
80
76
|
"Invalid arguments provided to SuperLink. Use `--help` check for the correct "
|
81
77
|
"usage. Alternatively, check the documentation."
|
82
78
|
),
|
83
|
-
# ServerApp-specific exit codes (200-299)
|
84
79
|
# SuperNode-specific exit codes (300-399)
|
85
80
|
ExitCode.SUPERNODE_REST_ADDRESS_INVALID: (
|
86
81
|
"When using the REST API, please provide `https://` or "
|
@@ -96,9 +91,8 @@ EXIT_CODE_HELP = {
|
|
96
91
|
"Please ensure that the file path points to a valid private/public key "
|
97
92
|
"file and try again."
|
98
93
|
),
|
99
|
-
#
|
100
|
-
#
|
101
|
-
# Common exit codes (600-)
|
94
|
+
# SuperExec-specific exit codes (400-499)
|
95
|
+
# Common exit codes (600-699)
|
102
96
|
ExitCode.COMMON_ADDRESS_INVALID: (
|
103
97
|
"Please provide a valid URL, IPv4 or IPv6 address."
|
104
98
|
),
|
flwr/server/app.py
CHANGED
@@ -37,7 +37,7 @@ from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
|
|
37
37
|
from flwr.common.address import parse_address
|
38
38
|
from flwr.common.args import try_obtain_server_certificates
|
39
39
|
from flwr.common.auth_plugin import ControlAuthPlugin, ControlAuthzPlugin
|
40
|
-
from flwr.common.config import get_flwr_dir
|
40
|
+
from flwr.common.config import get_flwr_dir
|
41
41
|
from flwr.common.constant import (
|
42
42
|
AUTH_TYPE_YAML_KEY,
|
43
43
|
AUTHZ_TYPE_YAML_KEY,
|
@@ -71,7 +71,6 @@ from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
|
|
71
71
|
from flwr.server.fleet_event_log_interceptor import FleetEventLogInterceptor
|
72
72
|
from flwr.supercore.ffs import FfsFactory
|
73
73
|
from flwr.supercore.object_store import ObjectStoreFactory
|
74
|
-
from flwr.superlink.executor import load_executor
|
75
74
|
from flwr.superlink.servicer.control import run_control_api_grpc
|
76
75
|
|
77
76
|
from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
|
@@ -136,6 +135,15 @@ def run_superlink() -> None:
|
|
136
135
|
WARN, "The `--flwr-dir` option is currently not in use and will be ignored."
|
137
136
|
)
|
138
137
|
|
138
|
+
# Detect if `--executor*` arguments were set
|
139
|
+
if args.executor or args.executor_dir or args.executor_config:
|
140
|
+
flwr_exit(
|
141
|
+
ExitCode.SUPERLINK_INVALID_ARGS,
|
142
|
+
"The arguments `--executor`, `--executor-dir`, and `--executor-config` are "
|
143
|
+
"deprecated and will be removed in a future release. To run SuperLink with "
|
144
|
+
"the SimulationIo API, please use `--simulation`.",
|
145
|
+
)
|
146
|
+
|
139
147
|
# Detect if both Control API and Exec API addresses were set explicitly
|
140
148
|
explicit_args = set()
|
141
149
|
for arg in sys.argv[1:]:
|
@@ -198,26 +206,19 @@ def run_superlink() -> None:
|
|
198
206
|
objectstore_factory = ObjectStoreFactory()
|
199
207
|
|
200
208
|
# Start Control API
|
201
|
-
|
209
|
+
is_simulation = args.simulation
|
202
210
|
control_server: grpc.Server = run_control_api_grpc(
|
203
211
|
address=control_address,
|
204
212
|
state_factory=state_factory,
|
205
213
|
ffs_factory=ffs_factory,
|
206
214
|
objectstore_factory=objectstore_factory,
|
207
|
-
executor=executor,
|
208
215
|
certificates=certificates,
|
209
|
-
|
210
|
-
[args.executor_config] if args.executor_config else args.executor_config
|
211
|
-
),
|
216
|
+
is_simulation=is_simulation,
|
212
217
|
auth_plugin=auth_plugin,
|
213
218
|
authz_plugin=authz_plugin,
|
214
219
|
event_log_plugin=event_log_plugin,
|
215
220
|
)
|
216
221
|
grpc_servers = [control_server]
|
217
|
-
|
218
|
-
# Determine Exec plugin
|
219
|
-
# If simulation is used, don't start ServerAppIo and Fleet APIs
|
220
|
-
is_simulation = executor.__class__.__qualname__ == "SimulationEngine"
|
221
222
|
bckg_threads: list[threading.Thread] = []
|
222
223
|
|
223
224
|
if is_simulation:
|
@@ -518,7 +519,9 @@ def _run_fleet_api_grpc_rere( # pylint: disable=R0913, R0917
|
|
518
519
|
interceptors=interceptors,
|
519
520
|
)
|
520
521
|
|
521
|
-
log(
|
522
|
+
log(
|
523
|
+
INFO, "Flower Deployment Runtime: Starting Fleet API (gRPC-rere) on %s", address
|
524
|
+
)
|
522
525
|
fleet_grpc_server.start()
|
523
526
|
|
524
527
|
return fleet_grpc_server
|
@@ -546,7 +549,11 @@ def _run_fleet_api_grpc_adapter(
|
|
546
549
|
certificates=certificates,
|
547
550
|
)
|
548
551
|
|
549
|
-
log(
|
552
|
+
log(
|
553
|
+
INFO,
|
554
|
+
"Flower Deployment Runtime: Starting Fleet API (GrpcAdapter) on %s",
|
555
|
+
address,
|
556
|
+
)
|
550
557
|
fleet_grpc_server.start()
|
551
558
|
|
552
559
|
return fleet_grpc_server
|
@@ -741,20 +748,25 @@ def _add_args_control_api(parser: argparse.ArgumentParser) -> None:
|
|
741
748
|
)
|
742
749
|
parser.add_argument(
|
743
750
|
"--executor",
|
744
|
-
help="
|
745
|
-
|
746
|
-
default="flwr.superexec.deployment:executor",
|
751
|
+
help="This argument is deprecated and will be removed in a future release.",
|
752
|
+
default=None,
|
747
753
|
)
|
748
754
|
parser.add_argument(
|
749
755
|
"--executor-dir",
|
750
|
-
help="
|
751
|
-
default=
|
756
|
+
help="This argument is deprecated and will be removed in a future release.",
|
757
|
+
default=None,
|
752
758
|
)
|
753
759
|
parser.add_argument(
|
754
760
|
"--executor-config",
|
755
|
-
help="
|
756
|
-
|
757
|
-
|
761
|
+
help="This argument is deprecated and will be removed in a future release.",
|
762
|
+
default=None,
|
763
|
+
)
|
764
|
+
parser.add_argument(
|
765
|
+
"--simulation",
|
766
|
+
action="store_true",
|
767
|
+
default=False,
|
768
|
+
help="Launch the SimulationIo API server in place of "
|
769
|
+
"the ServerAppIo API server.",
|
758
770
|
)
|
759
771
|
|
760
772
|
|
flwr/server/grid/grpc_grid.py
CHANGED
flwr/server/serverapp/app.py
CHANGED
@@ -16,7 +16,6 @@
|
|
16
16
|
|
17
17
|
|
18
18
|
import argparse
|
19
|
-
import gc
|
20
19
|
from logging import DEBUG, ERROR, INFO
|
21
20
|
from pathlib import Path
|
22
21
|
from queue import Queue
|
@@ -65,7 +64,7 @@ from flwr.proto.run_pb2 import UpdateRunStatusRequest # pylint: disable=E0611
|
|
65
64
|
from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
|
66
65
|
from flwr.server.grid.grpc_grid import GrpcGrid
|
67
66
|
from flwr.server.run_serverapp import run as run_
|
68
|
-
from flwr.supercore.app_utils import
|
67
|
+
from flwr.supercore.app_utils import start_parent_process_monitor
|
69
68
|
from flwr.supercore.superexec.plugin import ServerAppExecPlugin
|
70
69
|
from flwr.supercore.superexec.run_superexec import run_with_deprecation_warning
|
71
70
|
|
@@ -109,7 +108,6 @@ def flwr_serverapp() -> None:
|
|
109
108
|
serverappio_api_address=args.serverappio_api_address,
|
110
109
|
log_queue=log_queue,
|
111
110
|
token=args.token,
|
112
|
-
run_once=(args.token is not None) or args.run_once,
|
113
111
|
flwr_dir=args.flwr_dir,
|
114
112
|
certificates=None,
|
115
113
|
parent_pid=args.parent_pid,
|
@@ -122,8 +120,7 @@ def flwr_serverapp() -> None:
|
|
122
120
|
def run_serverapp( # pylint: disable=R0913, R0914, R0915, R0917, W0212
|
123
121
|
serverappio_api_address: str,
|
124
122
|
log_queue: Queue[Optional[str]],
|
125
|
-
|
126
|
-
token: Optional[str] = None,
|
123
|
+
token: str,
|
127
124
|
flwr_dir: Optional[str] = None,
|
128
125
|
certificates: Optional[bytes] = None,
|
129
126
|
parent_pid: Optional[int] = None,
|
@@ -142,154 +139,133 @@ def run_serverapp( # pylint: disable=R0913, R0914, R0915, R0917, W0212
|
|
142
139
|
heartbeat_sender = None
|
143
140
|
grid = None
|
144
141
|
context = None
|
145
|
-
while True:
|
146
142
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
143
|
+
try:
|
144
|
+
# Initialize the GrpcGrid
|
145
|
+
grid = GrpcGrid(
|
146
|
+
serverappio_service_address=serverappio_api_address,
|
147
|
+
root_certificates=certificates,
|
148
|
+
)
|
153
149
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
log(DEBUG, "[flwr-serverapp] Pull ServerAppInputs")
|
162
|
-
res: PullAppInputsResponse = grid._stub.PullAppInputs(req)
|
163
|
-
context = context_from_proto(res.context)
|
164
|
-
run = run_from_proto(res.run)
|
165
|
-
fab = fab_from_proto(res.fab)
|
166
|
-
|
167
|
-
hash_run_id = get_sha256_hash(run.run_id)
|
168
|
-
|
169
|
-
grid.set_run(run.run_id)
|
170
|
-
|
171
|
-
# Start log uploader for this run
|
172
|
-
log_uploader = start_log_uploader(
|
173
|
-
log_queue=log_queue,
|
174
|
-
node_id=0,
|
175
|
-
run_id=run.run_id,
|
176
|
-
stub=grid._stub,
|
177
|
-
)
|
150
|
+
# Pull ServerAppInputs from LinkState
|
151
|
+
req = PullAppInputsRequest(token=token)
|
152
|
+
log(DEBUG, "[flwr-serverapp] Pull ServerAppInputs")
|
153
|
+
res: PullAppInputsResponse = grid._stub.PullAppInputs(req)
|
154
|
+
context = context_from_proto(res.context)
|
155
|
+
run = run_from_proto(res.run)
|
156
|
+
fab = fab_from_proto(res.fab)
|
178
157
|
|
179
|
-
|
180
|
-
install_from_fab(fab.content, flwr_dir=flwr_dir_, skip_prompt=True)
|
158
|
+
hash_run_id = get_sha256_hash(run.run_id)
|
181
159
|
|
182
|
-
|
160
|
+
grid.set_run(run.run_id)
|
183
161
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
162
|
+
# Start log uploader for this run
|
163
|
+
log_uploader = start_log_uploader(
|
164
|
+
log_queue=log_queue,
|
165
|
+
node_id=0,
|
166
|
+
run_id=run.run_id,
|
167
|
+
stub=grid._stub,
|
168
|
+
)
|
188
169
|
|
189
|
-
|
190
|
-
|
191
|
-
server_app_run_config = get_fused_config_from_dir(
|
192
|
-
Path(app_path), run.override_config
|
193
|
-
)
|
170
|
+
log(DEBUG, "[flwr-serverapp] Start FAB installation.")
|
171
|
+
install_from_fab(fab.content, flwr_dir=flwr_dir_, skip_prompt=True)
|
194
172
|
|
195
|
-
|
196
|
-
context.run_config = server_app_run_config
|
173
|
+
fab_id, fab_version = get_fab_metadata(fab.content)
|
197
174
|
|
198
|
-
|
199
|
-
|
200
|
-
"[flwr-serverapp] Will load ServerApp `%s` in %s",
|
201
|
-
server_app_attr,
|
202
|
-
app_path,
|
203
|
-
)
|
175
|
+
app_path = str(get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir_))
|
176
|
+
config = get_project_config(app_path)
|
204
177
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
178
|
+
# Obtain server app reference and the run config
|
179
|
+
server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
|
180
|
+
server_app_run_config = get_fused_config_from_dir(
|
181
|
+
Path(app_path), run.override_config
|
182
|
+
)
|
210
183
|
|
211
|
-
|
212
|
-
|
213
|
-
event_details={"run-id-hash": hash_run_id},
|
214
|
-
)
|
184
|
+
# Update run_config in context
|
185
|
+
context.run_config = server_app_run_config
|
215
186
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
)
|
223
|
-
heartbeat_sender = HeartbeatSender(heartbeat_fn)
|
224
|
-
heartbeat_sender.start()
|
225
|
-
|
226
|
-
# Load and run the ServerApp with the Grid
|
227
|
-
updated_context = run_(
|
228
|
-
grid=grid,
|
229
|
-
server_app_dir=app_path,
|
230
|
-
server_app_attr=server_app_attr,
|
231
|
-
context=context,
|
232
|
-
)
|
187
|
+
log(
|
188
|
+
DEBUG,
|
189
|
+
"[flwr-serverapp] Will load ServerApp `%s` in %s",
|
190
|
+
server_app_attr,
|
191
|
+
app_path,
|
192
|
+
)
|
233
193
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
194
|
+
# Change status to Running
|
195
|
+
run_status_proto = run_status_to_proto(RunStatus(Status.RUNNING, "", ""))
|
196
|
+
grid._stub.UpdateRunStatus(
|
197
|
+
UpdateRunStatusRequest(run_id=run.run_id, run_status=run_status_proto)
|
198
|
+
)
|
199
|
+
|
200
|
+
event(
|
201
|
+
EventType.FLWR_SERVERAPP_RUN_ENTER,
|
202
|
+
event_details={"run-id-hash": hash_run_id},
|
203
|
+
)
|
204
|
+
|
205
|
+
# Set up heartbeat sender
|
206
|
+
heartbeat_fn = get_grpc_app_heartbeat_fn(
|
207
|
+
grid._stub,
|
208
|
+
run.run_id,
|
209
|
+
failure_message="Heartbeat failed unexpectedly. The SuperLink could "
|
210
|
+
"not find the provided run ID, or the run status is invalid.",
|
211
|
+
)
|
212
|
+
heartbeat_sender = HeartbeatSender(heartbeat_fn)
|
213
|
+
heartbeat_sender.start()
|
214
|
+
|
215
|
+
# Load and run the ServerApp with the Grid
|
216
|
+
updated_context = run_(
|
217
|
+
grid=grid,
|
218
|
+
server_app_dir=app_path,
|
219
|
+
server_app_attr=server_app_attr,
|
220
|
+
context=context,
|
221
|
+
)
|
222
|
+
|
223
|
+
# Send resulting context
|
224
|
+
context_proto = context_to_proto(updated_context)
|
225
|
+
log(DEBUG, "[flwr-serverapp] Will push ServerAppOutputs")
|
226
|
+
out_req = PushAppOutputsRequest(
|
227
|
+
token=token, run_id=run.run_id, context=context_proto
|
228
|
+
)
|
229
|
+
_ = grid._stub.PushAppOutputs(out_req)
|
230
|
+
|
231
|
+
run_status = RunStatus(Status.FINISHED, SubStatus.COMPLETED, "")
|
232
|
+
except RunNotRunningException:
|
233
|
+
log(INFO, "")
|
234
|
+
log(INFO, "Run ID %s stopped.", run.run_id)
|
235
|
+
log(INFO, "")
|
236
|
+
run_status = None
|
237
|
+
success = False
|
238
|
+
|
239
|
+
except Exception as ex: # pylint: disable=broad-exception-caught
|
240
|
+
exc_entity = "ServerApp"
|
241
|
+
log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
|
242
|
+
run_status = RunStatus(Status.FINISHED, SubStatus.FAILED, str(ex))
|
243
|
+
success = False
|
244
|
+
|
245
|
+
finally:
|
246
|
+
# Stop heartbeat sender
|
247
|
+
if heartbeat_sender:
|
248
|
+
heartbeat_sender.stop()
|
249
|
+
|
250
|
+
# Stop log uploader for this run and upload final logs
|
251
|
+
if log_uploader:
|
252
|
+
stop_log_uploader(log_queue, log_uploader)
|
253
|
+
|
254
|
+
# Update run status
|
255
|
+
if run_status and grid:
|
256
|
+
run_status_proto = run_status_to_proto(run_status)
|
257
|
+
grid._stub.UpdateRunStatus(
|
258
|
+
UpdateRunStatusRequest(run_id=run.run_id, run_status=run_status_proto)
|
288
259
|
)
|
289
260
|
|
290
|
-
#
|
291
|
-
if
|
292
|
-
|
261
|
+
# Close the Grpc connection
|
262
|
+
if grid:
|
263
|
+
grid.close()
|
264
|
+
|
265
|
+
event(
|
266
|
+
EventType.FLWR_SERVERAPP_RUN_LEAVE,
|
267
|
+
event_details={"run-id-hash": hash_run_id, "success": success},
|
268
|
+
)
|
293
269
|
|
294
270
|
|
295
271
|
def _parse_args_run_flwr_serverapp() -> argparse.ArgumentParser:
|
@@ -58,7 +58,7 @@ def run_serverappio_api_grpc(
|
|
58
58
|
certificates=certificates,
|
59
59
|
)
|
60
60
|
|
61
|
-
log(INFO, "Flower
|
61
|
+
log(INFO, "Flower Deployment Runtime: Starting ServerAppIo API on %s", address)
|
62
62
|
serverappio_grpc_server.start()
|
63
63
|
|
64
64
|
return serverappio_grpc_server
|