flwr-nightly 1.23.0.dev20251020__py3-none-any.whl → 1.23.0.dev20251022__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/ls.py +5 -5
- flwr/cli/supernode/ls.py +8 -15
- flwr/common/constant.py +12 -4
- flwr/common/inflatable_utils.py +10 -10
- flwr/common/record/array.py +3 -3
- flwr/proto/control_pb2.py +6 -6
- flwr/proto/control_pb2.pyi +0 -5
- flwr/server/app.py +4 -6
- flwr/server/superlink/fleet/vce/vce_api.py +2 -1
- flwr/server/superlink/linkstate/in_memory_linkstate.py +5 -1
- flwr/server/superlink/linkstate/linkstate_factory.py +2 -1
- flwr/server/superlink/linkstate/sqlite_linkstate.py +64 -146
- flwr/server/superlink/linkstate/utils.py +3 -54
- flwr/simulation/run_simulation.py +2 -1
- flwr/supercore/constant.py +3 -0
- flwr/supercore/object_store/object_store_factory.py +26 -6
- flwr/supercore/object_store/sqlite_object_store.py +252 -0
- flwr/supercore/sqlite_mixin.py +156 -0
- flwr/supercore/utils.py +20 -0
- flwr/superlink/servicer/control/control_servicer.py +6 -70
- {flwr_nightly-1.23.0.dev20251020.dist-info → flwr_nightly-1.23.0.dev20251022.dist-info}/METADATA +1 -1
- {flwr_nightly-1.23.0.dev20251020.dist-info → flwr_nightly-1.23.0.dev20251022.dist-info}/RECORD +24 -22
- {flwr_nightly-1.23.0.dev20251020.dist-info → flwr_nightly-1.23.0.dev20251022.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.23.0.dev20251020.dist-info → flwr_nightly-1.23.0.dev20251022.dist-info}/entry_points.txt +0 -0
flwr/cli/ls.py
CHANGED
|
@@ -220,14 +220,14 @@ def _to_table(run_list: list[_RunListType]) -> Table:
|
|
|
220
220
|
|
|
221
221
|
# Add columns
|
|
222
222
|
table.add_column(
|
|
223
|
-
Text("Run ID", justify="center"), style="
|
|
223
|
+
Text("Run ID", justify="center"), style="bright_black", no_wrap=True
|
|
224
224
|
)
|
|
225
|
-
table.add_column(Text("FAB", justify="center"), style="
|
|
225
|
+
table.add_column(Text("FAB", justify="center"), style="bright_black")
|
|
226
226
|
table.add_column(Text("Status", justify="center"))
|
|
227
227
|
table.add_column(Text("Elapsed", justify="center"), style="blue")
|
|
228
|
-
table.add_column(Text("Created At", justify="center"), style="
|
|
229
|
-
table.add_column(Text("Running At", justify="center"), style="
|
|
230
|
-
table.add_column(Text("Finished At", justify="center"), style="
|
|
228
|
+
table.add_column(Text("Created At", justify="center"), style="bright_black")
|
|
229
|
+
table.add_column(Text("Running At", justify="center"), style="bright_black")
|
|
230
|
+
table.add_column(Text("Finished At", justify="center"), style="bright_black")
|
|
231
231
|
|
|
232
232
|
for row in run_list:
|
|
233
233
|
(
|
flwr/cli/supernode/ls.py
CHANGED
|
@@ -32,7 +32,7 @@ from flwr.cli.config_utils import (
|
|
|
32
32
|
process_loaded_project_config,
|
|
33
33
|
validate_federation_in_project_config,
|
|
34
34
|
)
|
|
35
|
-
from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat
|
|
35
|
+
from flwr.common.constant import FAB_CONFIG_FILE, NOOP_FLWR_AID, CliOutputFormat
|
|
36
36
|
from flwr.common.date import format_timedelta, isoformat8601_utc
|
|
37
37
|
from flwr.common.logger import print_json_error, redirect_output, restore_output
|
|
38
38
|
from flwr.proto.control_pb2 import ( # pylint: disable=E0611
|
|
@@ -73,13 +73,6 @@ def ls( # pylint: disable=R0914, R0913, R0917
|
|
|
73
73
|
help="Enable verbose output",
|
|
74
74
|
),
|
|
75
75
|
] = False,
|
|
76
|
-
dry_run: Annotated[
|
|
77
|
-
bool,
|
|
78
|
-
typer.Option(
|
|
79
|
-
"--dry-run",
|
|
80
|
-
help="Simulate the command without contacting any SuperNodes",
|
|
81
|
-
),
|
|
82
|
-
] = False,
|
|
83
76
|
) -> None:
|
|
84
77
|
"""List SuperNodes in the federation."""
|
|
85
78
|
# Resolve command used (list or ls)
|
|
@@ -105,7 +98,7 @@ def ls( # pylint: disable=R0914, R0913, R0917
|
|
|
105
98
|
channel = init_channel(app, federation_config, auth_plugin)
|
|
106
99
|
stub = ControlStub(channel)
|
|
107
100
|
typer.echo("📄 Listing all nodes...")
|
|
108
|
-
formatted_nodes = _list_nodes(stub
|
|
101
|
+
formatted_nodes = _list_nodes(stub)
|
|
109
102
|
restore_output()
|
|
110
103
|
if output_format == CliOutputFormat.JSON:
|
|
111
104
|
Console().print_json(_to_json(formatted_nodes, verbose=verbose))
|
|
@@ -132,10 +125,10 @@ def ls( # pylint: disable=R0914, R0913, R0917
|
|
|
132
125
|
captured_output.close()
|
|
133
126
|
|
|
134
127
|
|
|
135
|
-
def _list_nodes(stub: ControlStub
|
|
128
|
+
def _list_nodes(stub: ControlStub) -> list[_NodeListType]:
|
|
136
129
|
"""List all nodes."""
|
|
137
130
|
with flwr_cli_grpc_exc_handler():
|
|
138
|
-
res: ListNodesResponse = stub.ListNodes(ListNodesRequest(
|
|
131
|
+
res: ListNodesResponse = stub.ListNodes(ListNodesRequest())
|
|
139
132
|
|
|
140
133
|
return _format_nodes(list(res.nodes_info), res.now)
|
|
141
134
|
|
|
@@ -185,12 +178,12 @@ def _to_table(nodes_info: list[_NodeListType], verbose: bool) -> Table:
|
|
|
185
178
|
|
|
186
179
|
# Add columns
|
|
187
180
|
table.add_column(
|
|
188
|
-
Text("Node ID", justify="center"), style="
|
|
181
|
+
Text("Node ID", justify="center"), style="bright_black", no_wrap=True
|
|
189
182
|
)
|
|
190
|
-
table.add_column(Text("Owner", justify="center")
|
|
183
|
+
table.add_column(Text("Owner", justify="center"))
|
|
191
184
|
table.add_column(Text("Status", justify="center"))
|
|
192
185
|
table.add_column(Text("Elapsed", justify="center"))
|
|
193
|
-
table.add_column(Text("Status Changed @", justify="center"), style="
|
|
186
|
+
table.add_column(Text("Status Changed @", justify="center"), style="bright_black")
|
|
194
187
|
|
|
195
188
|
for row in nodes_info:
|
|
196
189
|
(
|
|
@@ -223,7 +216,7 @@ def _to_table(nodes_info: list[_NodeListType], verbose: bool) -> Table:
|
|
|
223
216
|
|
|
224
217
|
formatted_row = (
|
|
225
218
|
f"[bold]{node_id}[/bold]",
|
|
226
|
-
f"{owner_aid}",
|
|
219
|
+
f"{owner_aid}" if owner_aid != NOOP_FLWR_AID else f"[dim]{owner_aid}[/dim]",
|
|
227
220
|
f"[{status_style}]{status}",
|
|
228
221
|
f"[cyan]{elapse_activated}[/cyan]" if status == "online" else "",
|
|
229
222
|
time_at,
|
flwr/common/constant.py
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import os
|
|
21
|
+
|
|
20
22
|
TRANSPORT_TYPE_GRPC_BIDI = "grpc-bidi"
|
|
21
23
|
TRANSPORT_TYPE_GRPC_RERE = "grpc-rere"
|
|
22
24
|
TRANSPORT_TYPE_GRPC_ADAPTER = "grpc-adapter"
|
|
@@ -135,7 +137,9 @@ GC_THRESHOLD = 200_000_000 # 200 MB
|
|
|
135
137
|
# Constants for Inflatable
|
|
136
138
|
HEAD_BODY_DIVIDER = b"\x00"
|
|
137
139
|
HEAD_VALUE_DIVIDER = " "
|
|
138
|
-
|
|
140
|
+
FLWR_PRIVATE_MAX_ARRAY_CHUNK_SIZE = int(
|
|
141
|
+
os.getenv("FLWR_PRIVATE_MAX_ARRAY_CHUNK_SIZE", "5242880")
|
|
142
|
+
) # 5 MB
|
|
139
143
|
|
|
140
144
|
# Constants for serialization
|
|
141
145
|
INT64_MAX_VALUE = 9223372036854775807 # (1 << 63) - 1
|
|
@@ -144,8 +148,12 @@ INT64_MAX_VALUE = 9223372036854775807 # (1 << 63) - 1
|
|
|
144
148
|
FLWR_APP_TOKEN_LENGTH = 128 # Length of the token used
|
|
145
149
|
|
|
146
150
|
# Constants for object pushing and pulling
|
|
147
|
-
|
|
148
|
-
|
|
151
|
+
FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PUSHES = int(
|
|
152
|
+
os.getenv("FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PUSHES", "2")
|
|
153
|
+
) # Default maximum number of concurrent pushes
|
|
154
|
+
FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PULLS = int(
|
|
155
|
+
os.getenv("FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PULLS", "2")
|
|
156
|
+
) # Default maximum number of concurrent pulls
|
|
149
157
|
PULL_MAX_TIME = 7200 # Default maximum time to wait for pulling objects
|
|
150
158
|
PULL_MAX_TRIES_PER_OBJECT = 500 # Default maximum number of tries to pull an object
|
|
151
159
|
PULL_INITIAL_BACKOFF = 1 # Initial backoff time for pulling objects
|
|
@@ -299,5 +307,5 @@ class ExecPluginType:
|
|
|
299
307
|
|
|
300
308
|
|
|
301
309
|
# Constants for No-op auth plugins
|
|
302
|
-
NOOP_FLWR_AID = "
|
|
310
|
+
NOOP_FLWR_AID = "<none>"
|
|
303
311
|
NOOP_ACCOUNT_NAME = "sys_noauth"
|
flwr/common/inflatable_utils.py
CHANGED
|
@@ -25,10 +25,10 @@ from typing import Callable, Optional, TypeVar
|
|
|
25
25
|
from flwr.proto.message_pb2 import ObjectTree # pylint: disable=E0611
|
|
26
26
|
|
|
27
27
|
from .constant import (
|
|
28
|
+
FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PULLS,
|
|
29
|
+
FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PUSHES,
|
|
28
30
|
HEAD_BODY_DIVIDER,
|
|
29
31
|
HEAD_VALUE_DIVIDER,
|
|
30
|
-
MAX_CONCURRENT_PULLS,
|
|
31
|
-
MAX_CONCURRENT_PUSHES,
|
|
32
32
|
PULL_BACKOFF_CAP,
|
|
33
33
|
PULL_INITIAL_BACKOFF,
|
|
34
34
|
PULL_MAX_TIME,
|
|
@@ -118,7 +118,7 @@ def push_objects(
|
|
|
118
118
|
*,
|
|
119
119
|
object_ids_to_push: Optional[set[str]] = None,
|
|
120
120
|
keep_objects: bool = False,
|
|
121
|
-
max_concurrent_pushes: int =
|
|
121
|
+
max_concurrent_pushes: int = FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PUSHES,
|
|
122
122
|
) -> None:
|
|
123
123
|
"""Push multiple objects to the servicer.
|
|
124
124
|
|
|
@@ -137,7 +137,7 @@ def push_objects(
|
|
|
137
137
|
If `True`, the original objects will be kept in the `objects` dictionary
|
|
138
138
|
after pushing. If `False`, they will be removed from the dictionary to avoid
|
|
139
139
|
high memory usage.
|
|
140
|
-
max_concurrent_pushes : int (default:
|
|
140
|
+
max_concurrent_pushes : int (default: FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PUSHES)
|
|
141
141
|
The maximum number of concurrent pushes to perform.
|
|
142
142
|
"""
|
|
143
143
|
lock = threading.Lock()
|
|
@@ -168,7 +168,7 @@ def push_object_contents_from_iterable(
|
|
|
168
168
|
object_contents: Iterable[tuple[str, bytes]],
|
|
169
169
|
push_object_fn: Callable[[str, bytes], None],
|
|
170
170
|
*,
|
|
171
|
-
max_concurrent_pushes: int =
|
|
171
|
+
max_concurrent_pushes: int = FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PUSHES,
|
|
172
172
|
) -> None:
|
|
173
173
|
"""Push multiple object contents to the servicer.
|
|
174
174
|
|
|
@@ -181,7 +181,7 @@ def push_object_contents_from_iterable(
|
|
|
181
181
|
A function that takes an object ID and its content as bytes, and pushes
|
|
182
182
|
it to the servicer. This function should raise `ObjectIdNotPreregisteredError`
|
|
183
183
|
if the object ID is not pre-registered.
|
|
184
|
-
max_concurrent_pushes : int (default:
|
|
184
|
+
max_concurrent_pushes : int (default: FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PUSHES)
|
|
185
185
|
The maximum number of concurrent pushes to perform.
|
|
186
186
|
"""
|
|
187
187
|
|
|
@@ -210,7 +210,7 @@ def pull_objects( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
210
210
|
object_ids: list[str],
|
|
211
211
|
pull_object_fn: Callable[[str], bytes],
|
|
212
212
|
*,
|
|
213
|
-
max_concurrent_pulls: int =
|
|
213
|
+
max_concurrent_pulls: int = FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PULLS,
|
|
214
214
|
max_time: Optional[float] = PULL_MAX_TIME,
|
|
215
215
|
max_tries_per_object: Optional[int] = PULL_MAX_TRIES_PER_OBJECT,
|
|
216
216
|
initial_backoff: float = PULL_INITIAL_BACKOFF,
|
|
@@ -227,7 +227,7 @@ def pull_objects( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
227
227
|
The function should raise `ObjectUnavailableError` if the object is not yet
|
|
228
228
|
available, or `ObjectIdNotPreregisteredError` if the object ID is not
|
|
229
229
|
pre-registered.
|
|
230
|
-
max_concurrent_pulls : int (default:
|
|
230
|
+
max_concurrent_pulls : int (default: FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PULLS)
|
|
231
231
|
The maximum number of concurrent pulls to perform.
|
|
232
232
|
max_time : Optional[float] (default: PULL_MAX_TIME)
|
|
233
233
|
The maximum time to wait for all pulls to complete. If `None`, waits
|
|
@@ -442,7 +442,7 @@ def pull_and_inflate_object_from_tree( # pylint: disable=R0913
|
|
|
442
442
|
confirm_object_received_fn: Callable[[str], None],
|
|
443
443
|
*,
|
|
444
444
|
return_type: type[T] = InflatableObject, # type: ignore
|
|
445
|
-
max_concurrent_pulls: int =
|
|
445
|
+
max_concurrent_pulls: int = FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PULLS,
|
|
446
446
|
max_time: Optional[float] = PULL_MAX_TIME,
|
|
447
447
|
max_tries_per_object: Optional[int] = PULL_MAX_TRIES_PER_OBJECT,
|
|
448
448
|
initial_backoff: float = PULL_INITIAL_BACKOFF,
|
|
@@ -460,7 +460,7 @@ def pull_and_inflate_object_from_tree( # pylint: disable=R0913
|
|
|
460
460
|
A function to confirm that the object has been received.
|
|
461
461
|
return_type : type[T] (default: InflatableObject)
|
|
462
462
|
The type of the object to return. Must be a subclass of `InflatableObject`.
|
|
463
|
-
max_concurrent_pulls : int (default:
|
|
463
|
+
max_concurrent_pulls : int (default: FLWR_PRIVATE_MAX_CONCURRENT_OBJ_PULLS)
|
|
464
464
|
The maximum number of concurrent pulls to perform.
|
|
465
465
|
max_time : Optional[float] (default: PULL_MAX_TIME)
|
|
466
466
|
The maximum time to wait for all pulls to complete. If `None`, waits
|
flwr/common/record/array.py
CHANGED
|
@@ -25,7 +25,7 @@ from typing import TYPE_CHECKING, Any, cast, overload
|
|
|
25
25
|
|
|
26
26
|
import numpy as np
|
|
27
27
|
|
|
28
|
-
from ..constant import
|
|
28
|
+
from ..constant import FLWR_PRIVATE_MAX_ARRAY_CHUNK_SIZE, SType
|
|
29
29
|
from ..inflatable import (
|
|
30
30
|
InflatableObject,
|
|
31
31
|
add_header_to_object_body,
|
|
@@ -272,8 +272,8 @@ class Array(InflatableObject):
|
|
|
272
272
|
chunks: list[tuple[str, InflatableObject]] = []
|
|
273
273
|
# memoryview allows for zero-copy slicing
|
|
274
274
|
data_view = memoryview(self.data)
|
|
275
|
-
for start in range(0, len(data_view),
|
|
276
|
-
end = min(start +
|
|
275
|
+
for start in range(0, len(data_view), FLWR_PRIVATE_MAX_ARRAY_CHUNK_SIZE):
|
|
276
|
+
end = min(start + FLWR_PRIVATE_MAX_ARRAY_CHUNK_SIZE, len(data_view))
|
|
277
277
|
ac = ArrayChunk(data_view[start:end])
|
|
278
278
|
chunks.append((ac.object_id, ac))
|
|
279
279
|
|
flwr/proto/control_pb2.py
CHANGED
|
@@ -19,7 +19,7 @@ from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
|
|
19
19
|
from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/control.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x1b\x66lwr/proto/recorddict.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x15\x66lwr/proto/node.proto\"\xfa\x01\n\x0fStartRunRequest\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fab\x12H\n\x0foverride_config\x18\x02 \x03(\x0b\x32/.flwr.proto.StartRunRequest.OverrideConfigEntry\x12\x34\n\x12\x66\x65\x64\x65ration_options\x18\x03 \x01(\x0b\x32\x18.flwr.proto.ConfigRecord\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\"2\n\x10StartRunResponse\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"<\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x17\n\x0f\x61\x66ter_timestamp\x18\x02 \x01(\x01\"B\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t\x12\x18\n\x10latest_timestamp\x18\x02 \x01(\x01\"1\n\x0fListRunsRequest\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"\x9d\x01\n\x10ListRunsResponse\x12;\n\x08run_dict\x18\x01 \x03(\x0b\x32).flwr.proto.ListRunsResponse.RunDictEntry\x12\x0b\n\x03now\x18\x02 \x01(\t\x1a?\n\x0cRunDictEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.flwr.proto.Run:\x02\x38\x01\"\x18\n\x16GetLoginDetailsRequest\"\x8b\x01\n\x17GetLoginDetailsResponse\x12\x12\n\nauthn_type\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_code\x18\x02 \x01(\t\x12!\n\x19verification_uri_complete\x18\x03 \x01(\t\x12\x12\n\nexpires_in\x18\x04 \x01(\x03\x12\x10\n\x08interval\x18\x05 \x01(\x03\"+\n\x14GetAuthTokensRequest\x12\x13\n\x0b\x64\x65vice_code\x18\x01 \x01(\t\"D\n\x15GetAuthTokensResponse\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\t\x12\x15\n\rrefresh_token\x18\x02 \x01(\t\" \n\x0eStopRunRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"\"\n\x0fStopRunResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"&\n\x14PullArtifactsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"1\n\x15PullArtifactsResponse\x12\x10\n\x03url\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_url\")\n\x13RegisterNodeRequest\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\"8\n\x14RegisterNodeResponse\x12\x14\n\x07node_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_node_id\"(\n\x15UnregisterNodeRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x04\"\x18\n\x16UnregisterNodeResponse\"
|
|
22
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/control.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x1b\x66lwr/proto/recorddict.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x15\x66lwr/proto/node.proto\"\xfa\x01\n\x0fStartRunRequest\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fab\x12H\n\x0foverride_config\x18\x02 \x03(\x0b\x32/.flwr.proto.StartRunRequest.OverrideConfigEntry\x12\x34\n\x12\x66\x65\x64\x65ration_options\x18\x03 \x01(\x0b\x32\x18.flwr.proto.ConfigRecord\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\"2\n\x10StartRunResponse\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"<\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x17\n\x0f\x61\x66ter_timestamp\x18\x02 \x01(\x01\"B\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t\x12\x18\n\x10latest_timestamp\x18\x02 \x01(\x01\"1\n\x0fListRunsRequest\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"\x9d\x01\n\x10ListRunsResponse\x12;\n\x08run_dict\x18\x01 \x03(\x0b\x32).flwr.proto.ListRunsResponse.RunDictEntry\x12\x0b\n\x03now\x18\x02 \x01(\t\x1a?\n\x0cRunDictEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.flwr.proto.Run:\x02\x38\x01\"\x18\n\x16GetLoginDetailsRequest\"\x8b\x01\n\x17GetLoginDetailsResponse\x12\x12\n\nauthn_type\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_code\x18\x02 \x01(\t\x12!\n\x19verification_uri_complete\x18\x03 \x01(\t\x12\x12\n\nexpires_in\x18\x04 \x01(\x03\x12\x10\n\x08interval\x18\x05 \x01(\x03\"+\n\x14GetAuthTokensRequest\x12\x13\n\x0b\x64\x65vice_code\x18\x01 \x01(\t\"D\n\x15GetAuthTokensResponse\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\t\x12\x15\n\rrefresh_token\x18\x02 \x01(\t\" \n\x0eStopRunRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"\"\n\x0fStopRunResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"&\n\x14PullArtifactsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"1\n\x15PullArtifactsResponse\x12\x10\n\x03url\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_url\")\n\x13RegisterNodeRequest\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\"8\n\x14RegisterNodeResponse\x12\x14\n\x07node_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_node_id\"(\n\x15UnregisterNodeRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x04\"\x18\n\x16UnregisterNodeResponse\"\x12\n\x10ListNodesRequest\"J\n\x11ListNodesResponse\x12(\n\nnodes_info\x18\x01 \x03(\x0b\x32\x14.flwr.proto.NodeInfo\x12\x0b\n\x03now\x18\x02 \x01(\t2\xbc\x06\n\x07\x43ontrol\x12G\n\x08StartRun\x12\x1b.flwr.proto.StartRunRequest\x1a\x1c.flwr.proto.StartRunResponse\"\x00\x12\x44\n\x07StopRun\x12\x1a.flwr.proto.StopRunRequest\x1a\x1b.flwr.proto.StopRunResponse\"\x00\x12O\n\nStreamLogs\x12\x1d.flwr.proto.StreamLogsRequest\x1a\x1e.flwr.proto.StreamLogsResponse\"\x00\x30\x01\x12G\n\x08ListRuns\x12\x1b.flwr.proto.ListRunsRequest\x1a\x1c.flwr.proto.ListRunsResponse\"\x00\x12\\\n\x0fGetLoginDetails\x12\".flwr.proto.GetLoginDetailsRequest\x1a#.flwr.proto.GetLoginDetailsResponse\"\x00\x12V\n\rGetAuthTokens\x12 .flwr.proto.GetAuthTokensRequest\x1a!.flwr.proto.GetAuthTokensResponse\"\x00\x12V\n\rPullArtifacts\x12 .flwr.proto.PullArtifactsRequest\x1a!.flwr.proto.PullArtifactsResponse\"\x00\x12S\n\x0cRegisterNode\x12\x1f.flwr.proto.RegisterNodeRequest\x1a .flwr.proto.RegisterNodeResponse\"\x00\x12Y\n\x0eUnregisterNode\x12!.flwr.proto.UnregisterNodeRequest\x1a\".flwr.proto.UnregisterNodeResponse\"\x00\x12J\n\tListNodes\x12\x1c.flwr.proto.ListNodesRequest\x1a\x1d.flwr.proto.ListNodesResponse\"\x00\x62\x06proto3')
|
|
23
23
|
|
|
24
24
|
_globals = globals()
|
|
25
25
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -71,9 +71,9 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
71
71
|
_globals['_UNREGISTERNODERESPONSE']._serialized_start=1397
|
|
72
72
|
_globals['_UNREGISTERNODERESPONSE']._serialized_end=1421
|
|
73
73
|
_globals['_LISTNODESREQUEST']._serialized_start=1423
|
|
74
|
-
_globals['_LISTNODESREQUEST']._serialized_end=
|
|
75
|
-
_globals['_LISTNODESRESPONSE']._serialized_start=
|
|
76
|
-
_globals['_LISTNODESRESPONSE']._serialized_end=
|
|
77
|
-
_globals['_CONTROL']._serialized_start=
|
|
78
|
-
_globals['_CONTROL']._serialized_end=
|
|
74
|
+
_globals['_LISTNODESREQUEST']._serialized_end=1441
|
|
75
|
+
_globals['_LISTNODESRESPONSE']._serialized_start=1443
|
|
76
|
+
_globals['_LISTNODESRESPONSE']._serialized_end=1517
|
|
77
|
+
_globals['_CONTROL']._serialized_start=1520
|
|
78
|
+
_globals['_CONTROL']._serialized_end=2348
|
|
79
79
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/control_pb2.pyi
CHANGED
|
@@ -279,13 +279,8 @@ global___UnregisterNodeResponse = UnregisterNodeResponse
|
|
|
279
279
|
|
|
280
280
|
class ListNodesRequest(google.protobuf.message.Message):
|
|
281
281
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
282
|
-
DRY_RUN_FIELD_NUMBER: builtins.int
|
|
283
|
-
dry_run: builtins.bool
|
|
284
282
|
def __init__(self,
|
|
285
|
-
*,
|
|
286
|
-
dry_run: builtins.bool = ...,
|
|
287
283
|
) -> None: ...
|
|
288
|
-
def ClearField(self, field_name: typing_extensions.Literal["dry_run",b"dry_run"]) -> None: ...
|
|
289
284
|
global___ListNodesRequest = ListNodesRequest
|
|
290
285
|
|
|
291
286
|
class ListNodesResponse(google.protobuf.message.Message):
|
flwr/server/app.py
CHANGED
|
@@ -64,6 +64,7 @@ from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
|
|
|
64
64
|
)
|
|
65
65
|
from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
|
|
66
66
|
from flwr.server.fleet_event_log_interceptor import FleetEventLogInterceptor
|
|
67
|
+
from flwr.supercore.constant import FLWR_IN_MEMORY_DB_NAME
|
|
67
68
|
from flwr.supercore.ffs import FfsFactory
|
|
68
69
|
from flwr.supercore.grpc_health import add_args_health, run_health_server_grpc_no_tls
|
|
69
70
|
from flwr.supercore.object_store import ObjectStoreFactory
|
|
@@ -85,7 +86,6 @@ from .superlink.linkstate import LinkStateFactory
|
|
|
85
86
|
from .superlink.serverappio.serverappio_grpc import run_serverappio_api_grpc
|
|
86
87
|
from .superlink.simulation.simulationio_grpc import run_simulationio_api_grpc
|
|
87
88
|
|
|
88
|
-
DATABASE = ":flwr-in-memory-state:"
|
|
89
89
|
BASE_DIR = get_flwr_dir() / "superlink" / "ffs"
|
|
90
90
|
P = TypeVar("P", ControlAuthnPlugin, ControlAuthzPlugin)
|
|
91
91
|
|
|
@@ -272,7 +272,7 @@ def run_superlink() -> None:
|
|
|
272
272
|
ffs_factory = FfsFactory(args.storage_dir)
|
|
273
273
|
|
|
274
274
|
# Initialize ObjectStoreFactory
|
|
275
|
-
objectstore_factory = ObjectStoreFactory()
|
|
275
|
+
objectstore_factory = ObjectStoreFactory(args.database)
|
|
276
276
|
|
|
277
277
|
# Start Control API
|
|
278
278
|
is_simulation = args.simulation
|
|
@@ -710,11 +710,9 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
710
710
|
parser.add_argument(
|
|
711
711
|
"--database",
|
|
712
712
|
help="A string representing the path to the database "
|
|
713
|
-
"file that will be opened.
|
|
714
|
-
"will open a connection to a database that is in RAM, "
|
|
715
|
-
"instead of on disk. If nothing is provided, "
|
|
713
|
+
"file that will be opened. If nothing is provided, "
|
|
716
714
|
"Flower will just create a state in memory.",
|
|
717
|
-
default=
|
|
715
|
+
default=FLWR_IN_MEMORY_DB_NAME,
|
|
718
716
|
)
|
|
719
717
|
parser.add_argument(
|
|
720
718
|
"--storage-dir",
|
|
@@ -42,6 +42,7 @@ from flwr.common.constant import (
|
|
|
42
42
|
from flwr.common.logger import log
|
|
43
43
|
from flwr.common.typing import Run
|
|
44
44
|
from flwr.server.superlink.linkstate import LinkState, LinkStateFactory
|
|
45
|
+
from flwr.supercore.constant import FLWR_IN_MEMORY_DB_NAME
|
|
45
46
|
|
|
46
47
|
from .backend import Backend, error_messages_backends, supported_backends
|
|
47
48
|
|
|
@@ -312,7 +313,7 @@ def start_vce(
|
|
|
312
313
|
if not state_factory:
|
|
313
314
|
log(INFO, "A StateFactory was not supplied to the SimulationEngine.")
|
|
314
315
|
# Create an empty in-memory state factory
|
|
315
|
-
state_factory = LinkStateFactory(
|
|
316
|
+
state_factory = LinkStateFactory(FLWR_IN_MEMORY_DB_NAME)
|
|
316
317
|
log(INFO, "Created new %s.", state_factory.__class__.__name__)
|
|
317
318
|
|
|
318
319
|
if num_supernodes:
|
|
@@ -262,6 +262,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
262
262
|
node_id: self.nodes[node_id].online_until
|
|
263
263
|
for node_id in dst_node_ids
|
|
264
264
|
if node_id in self.nodes
|
|
265
|
+
and self.nodes[node_id].status != NodeStatus.UNREGISTERED
|
|
265
266
|
},
|
|
266
267
|
current_time=current,
|
|
267
268
|
)
|
|
@@ -380,7 +381,10 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
380
381
|
)
|
|
381
382
|
|
|
382
383
|
node.status = NodeStatus.UNREGISTERED
|
|
383
|
-
|
|
384
|
+
current = now()
|
|
385
|
+
node.unregistered_at = current.isoformat()
|
|
386
|
+
# Set online_until to current timestamp on deletion, if it is in the future
|
|
387
|
+
node.online_until = min(node.online_until, current.timestamp())
|
|
384
388
|
|
|
385
389
|
def get_nodes(self, run_id: int) -> set[int]:
|
|
386
390
|
"""Return all available nodes.
|
|
@@ -19,6 +19,7 @@ from logging import DEBUG
|
|
|
19
19
|
from typing import Optional
|
|
20
20
|
|
|
21
21
|
from flwr.common.logger import log
|
|
22
|
+
from flwr.supercore.constant import FLWR_IN_MEMORY_DB_NAME
|
|
22
23
|
|
|
23
24
|
from .in_memory_linkstate import InMemoryLinkState
|
|
24
25
|
from .linkstate import LinkState
|
|
@@ -44,7 +45,7 @@ class LinkStateFactory:
|
|
|
44
45
|
def state(self) -> LinkState:
|
|
45
46
|
"""Return a State instance and create it, if necessary."""
|
|
46
47
|
# InMemoryState
|
|
47
|
-
if self.database ==
|
|
48
|
+
if self.database == FLWR_IN_MEMORY_DB_NAME:
|
|
48
49
|
if self.state_instance is None:
|
|
49
50
|
self.state_instance = InMemoryLinkState()
|
|
50
51
|
log(DEBUG, "Using InMemoryState")
|