flwr 1.15.2__py3-none-any.whl → 1.16.0__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.
Files changed (68) hide show
  1. flwr/cli/build.py +2 -0
  2. flwr/cli/log.py +20 -21
  3. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
  4. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
  5. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
  6. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
  7. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
  8. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
  9. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +1 -1
  10. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
  11. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
  12. flwr/client/client_app.py +147 -36
  13. flwr/client/clientapp/app.py +4 -0
  14. flwr/client/message_handler/message_handler.py +1 -1
  15. flwr/client/rest_client/connection.py +4 -6
  16. flwr/client/supernode/__init__.py +0 -2
  17. flwr/client/supernode/app.py +1 -11
  18. flwr/common/address.py +35 -0
  19. flwr/common/args.py +8 -2
  20. flwr/common/auth_plugin/auth_plugin.py +2 -1
  21. flwr/common/constant.py +16 -0
  22. flwr/common/event_log_plugin/__init__.py +22 -0
  23. flwr/common/event_log_plugin/event_log_plugin.py +60 -0
  24. flwr/common/grpc.py +1 -1
  25. flwr/common/message.py +18 -7
  26. flwr/common/object_ref.py +0 -10
  27. flwr/common/record/conversion_utils.py +8 -17
  28. flwr/common/record/parametersrecord.py +151 -16
  29. flwr/common/record/recordset.py +95 -88
  30. flwr/common/secure_aggregation/quantization.py +5 -1
  31. flwr/common/serde.py +8 -126
  32. flwr/common/telemetry.py +0 -10
  33. flwr/common/typing.py +36 -0
  34. flwr/server/app.py +18 -2
  35. flwr/server/compat/app.py +4 -1
  36. flwr/server/compat/app_utils.py +10 -2
  37. flwr/server/compat/driver_client_proxy.py +2 -2
  38. flwr/server/driver/driver.py +1 -1
  39. flwr/server/driver/grpc_driver.py +10 -1
  40. flwr/server/driver/inmemory_driver.py +17 -20
  41. flwr/server/run_serverapp.py +2 -13
  42. flwr/server/server_app.py +93 -20
  43. flwr/server/superlink/driver/serverappio_servicer.py +25 -27
  44. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +2 -2
  45. flwr/server/superlink/fleet/message_handler/message_handler.py +8 -12
  46. flwr/server/superlink/fleet/vce/backend/backend.py +1 -1
  47. flwr/server/superlink/fleet/vce/vce_api.py +32 -35
  48. flwr/server/superlink/linkstate/in_memory_linkstate.py +140 -126
  49. flwr/server/superlink/linkstate/linkstate.py +47 -60
  50. flwr/server/superlink/linkstate/sqlite_linkstate.py +210 -276
  51. flwr/server/superlink/linkstate/utils.py +91 -119
  52. flwr/server/utils/__init__.py +2 -2
  53. flwr/server/utils/validator.py +53 -68
  54. flwr/server/workflow/default_workflows.py +4 -1
  55. flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +3 -3
  56. flwr/superexec/app.py +0 -14
  57. flwr/superexec/exec_servicer.py +4 -4
  58. flwr/superexec/exec_user_auth_interceptor.py +5 -3
  59. {flwr-1.15.2.dist-info → flwr-1.16.0.dist-info}/METADATA +4 -4
  60. {flwr-1.15.2.dist-info → flwr-1.16.0.dist-info}/RECORD +63 -66
  61. {flwr-1.15.2.dist-info → flwr-1.16.0.dist-info}/entry_points.txt +0 -3
  62. flwr/client/message_handler/task_handler.py +0 -37
  63. flwr/proto/task_pb2.py +0 -33
  64. flwr/proto/task_pb2.pyi +0 -100
  65. flwr/proto/task_pb2_grpc.py +0 -4
  66. flwr/proto/task_pb2_grpc.pyi +0 -4
  67. {flwr-1.15.2.dist-info → flwr-1.16.0.dist-info}/LICENSE +0 -0
  68. {flwr-1.15.2.dist-info → flwr-1.16.0.dist-info}/WHEEL +0 -0
@@ -23,7 +23,7 @@ from logging import ERROR, WARNING
23
23
  from typing import Optional
24
24
  from uuid import UUID, uuid4
25
25
 
26
- from flwr.common import Context, log, now
26
+ from flwr.common import Context, Message, log, now
27
27
  from flwr.common.constant import (
28
28
  MESSAGE_TTL_TOLERANCE,
29
29
  NODE_ID_NUM_BYTES,
@@ -33,16 +33,15 @@ from flwr.common.constant import (
33
33
  )
34
34
  from flwr.common.record import ConfigsRecord
35
35
  from flwr.common.typing import Run, RunStatus, UserConfig
36
- from flwr.proto.task_pb2 import TaskIns, TaskRes # pylint: disable=E0611
37
36
  from flwr.server.superlink.linkstate.linkstate import LinkState
38
- from flwr.server.utils import validate_task_ins_or_res
37
+ from flwr.server.utils import validate_message
39
38
 
40
39
  from .utils import (
41
40
  generate_rand_int_from_bytes,
42
41
  has_valid_sub_status,
43
42
  is_valid_transition,
44
- verify_found_taskres,
45
- verify_taskins_ids,
43
+ verify_found_message_replies,
44
+ verify_message_ids,
46
45
  )
47
46
 
48
47
 
@@ -69,227 +68,242 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
69
68
  self.run_ids: dict[int, RunRecord] = {}
70
69
  self.contexts: dict[int, Context] = {}
71
70
  self.federation_options: dict[int, ConfigsRecord] = {}
72
- self.task_ins_store: dict[UUID, TaskIns] = {}
73
- self.task_res_store: dict[UUID, TaskRes] = {}
74
- self.task_ins_id_to_task_res_id: dict[UUID, UUID] = {}
71
+ self.message_ins_store: dict[UUID, Message] = {}
72
+ self.message_res_store: dict[UUID, Message] = {}
73
+ self.message_ins_id_to_message_res_id: dict[UUID, UUID] = {}
75
74
 
76
75
  self.node_public_keys: set[bytes] = set()
77
76
 
78
77
  self.lock = threading.RLock()
79
78
 
80
- def store_task_ins(self, task_ins: TaskIns) -> Optional[UUID]:
81
- """Store one TaskIns."""
82
- # Validate task
83
- errors = validate_task_ins_or_res(task_ins)
79
+ def store_message_ins(self, message: Message) -> Optional[UUID]:
80
+ """Store one Message."""
81
+ # Validate message
82
+ errors = validate_message(message, is_reply_message=False)
84
83
  if any(errors):
85
84
  log(ERROR, errors)
86
85
  return None
87
86
  # Validate run_id
88
- if task_ins.run_id not in self.run_ids:
89
- log(ERROR, "Invalid run ID for TaskIns: %s", task_ins.run_id)
87
+ if message.metadata.run_id not in self.run_ids:
88
+ log(ERROR, "Invalid run ID for Message: %s", message.metadata.run_id)
90
89
  return None
91
90
  # Validate source node ID
92
- if task_ins.task.producer.node_id != SUPERLINK_NODE_ID:
91
+ if message.metadata.src_node_id != SUPERLINK_NODE_ID:
93
92
  log(
94
93
  ERROR,
95
- "Invalid source node ID for TaskIns: %s",
96
- task_ins.task.producer.node_id,
94
+ "Invalid source node ID for Message: %s",
95
+ message.metadata.src_node_id,
97
96
  )
98
97
  return None
99
98
  # Validate destination node ID
100
- if task_ins.task.consumer.node_id not in self.node_ids:
99
+ if message.metadata.dst_node_id not in self.node_ids:
101
100
  log(
102
101
  ERROR,
103
- "Invalid destination node ID for TaskIns: %s",
104
- task_ins.task.consumer.node_id,
102
+ "Invalid destination node ID for Message: %s",
103
+ message.metadata.dst_node_id,
105
104
  )
106
105
  return None
107
106
 
108
- # Create task_id
109
- task_id = uuid4()
107
+ # Create message_id
108
+ message_id = uuid4()
110
109
 
111
- # Store TaskIns
112
- task_ins.task_id = str(task_id)
110
+ # Store Message
111
+ # pylint: disable-next=W0212
112
+ message.metadata._message_id = str(message_id) # type: ignore
113
113
  with self.lock:
114
- self.task_ins_store[task_id] = task_ins
114
+ self.message_ins_store[message_id] = message
115
115
 
116
- # Return the new task_id
117
- return task_id
116
+ # Return the new message_id
117
+ return message_id
118
118
 
119
- def get_task_ins(self, node_id: int, limit: Optional[int]) -> list[TaskIns]:
120
- """Get all TaskIns that have not been delivered yet."""
119
+ def get_message_ins(self, node_id: int, limit: Optional[int]) -> list[Message]:
120
+ """Get all Messages that have not been delivered yet."""
121
121
  if limit is not None and limit < 1:
122
122
  raise AssertionError("`limit` must be >= 1")
123
123
 
124
- # Find TaskIns for node_id that were not delivered yet
125
- task_ins_list: list[TaskIns] = []
124
+ # Find Message for node_id that were not delivered yet
125
+ message_ins_list: list[Message] = []
126
126
  current_time = time.time()
127
127
  with self.lock:
128
- for _, task_ins in self.task_ins_store.items():
128
+ for _, msg_ins in self.message_ins_store.items():
129
129
  if (
130
- task_ins.task.consumer.node_id == node_id
131
- and task_ins.task.delivered_at == ""
132
- and task_ins.task.created_at + task_ins.task.ttl > current_time
130
+ msg_ins.metadata.dst_node_id == node_id
131
+ and msg_ins.metadata.delivered_at == ""
132
+ and msg_ins.metadata.created_at + msg_ins.metadata.ttl
133
+ > current_time
133
134
  ):
134
- task_ins_list.append(task_ins)
135
- if limit and len(task_ins_list) == limit:
135
+ message_ins_list.append(msg_ins)
136
+ if limit and len(message_ins_list) == limit:
136
137
  break
137
138
 
138
139
  # Mark all of them as delivered
139
140
  delivered_at = now().isoformat()
140
- for task_ins in task_ins_list:
141
- task_ins.task.delivered_at = delivered_at
141
+ for msg_ins in message_ins_list:
142
+ msg_ins.metadata.delivered_at = delivered_at
142
143
 
143
- # Return TaskIns
144
- return task_ins_list
144
+ # Return list of messages
145
+ return message_ins_list
145
146
 
146
147
  # pylint: disable=R0911
147
- def store_task_res(self, task_res: TaskRes) -> Optional[UUID]:
148
- """Store one TaskRes."""
149
- # Validate task
150
- errors = validate_task_ins_or_res(task_res)
148
+ def store_message_res(self, message: Message) -> Optional[UUID]:
149
+ """Store one Message."""
150
+ # Validate message
151
+ errors = validate_message(message, is_reply_message=True)
151
152
  if any(errors):
152
153
  log(ERROR, errors)
153
154
  return None
154
155
 
156
+ res_metadata = message.metadata
155
157
  with self.lock:
156
- # Check if the TaskIns it is replying to exists and is valid
157
- task_ins_id = task_res.task.ancestry[0]
158
- task_ins = self.task_ins_store.get(UUID(task_ins_id))
158
+ # Check if the Message it is replying to exists and is valid
159
+ msg_ins_id = res_metadata.reply_to_message
160
+ msg_ins = self.message_ins_store.get(UUID(msg_ins_id))
159
161
 
160
- # Ensure that the consumer_id of taskIns matches the producer_id of taskRes.
162
+ # Ensure that dst_node_id of original Message matches the src_node_id of
163
+ # reply Message.
161
164
  if (
162
- task_ins
163
- and task_res
164
- and task_ins.task.consumer.node_id != task_res.task.producer.node_id
165
+ msg_ins
166
+ and message
167
+ and msg_ins.metadata.dst_node_id != res_metadata.src_node_id
165
168
  ):
166
169
  return None
167
170
 
168
- if task_ins is None:
169
- log(ERROR, "TaskIns with task_id %s does not exist.", task_ins_id)
171
+ if msg_ins is None:
172
+ log(
173
+ ERROR,
174
+ "Message with ID %s does not exist.",
175
+ msg_ins_id,
176
+ )
170
177
  return None
171
178
 
172
- if task_ins.task.created_at + task_ins.task.ttl <= time.time():
179
+ ins_metadata = msg_ins.metadata
180
+ if ins_metadata.created_at + ins_metadata.ttl <= time.time():
173
181
  log(
174
182
  ERROR,
175
- "Failed to store TaskRes: TaskIns with task_id %s has expired.",
176
- task_ins_id,
183
+ "Failed to store Message: the message it is replying to "
184
+ "(with ID %s) has expired",
185
+ msg_ins_id,
177
186
  )
178
187
  return None
179
188
 
180
- # Fail if the TaskRes TTL exceeds the
181
- # expiration time of the TaskIns it replies to.
182
- # Condition: TaskIns.created_at + TaskIns.ttl ≥
183
- # TaskRes.created_at + TaskRes.ttl
189
+ # Fail if the Message TTL exceeds the
190
+ # expiration time of the Message it replies to.
191
+ # Condition: ins_metadata.created_at + ins_metadata.ttl ≥
192
+ # res_metadata.created_at + res_metadata.ttl
184
193
  # A small tolerance is introduced to account
185
194
  # for floating-point precision issues.
186
195
  max_allowed_ttl = (
187
- task_ins.task.created_at + task_ins.task.ttl - task_res.task.created_at
196
+ ins_metadata.created_at + ins_metadata.ttl - res_metadata.created_at
188
197
  )
189
- if task_res.task.ttl and (
190
- task_res.task.ttl - max_allowed_ttl > MESSAGE_TTL_TOLERANCE
198
+ if res_metadata.ttl and (
199
+ res_metadata.ttl - max_allowed_ttl > MESSAGE_TTL_TOLERANCE
191
200
  ):
192
201
  log(
193
202
  WARNING,
194
- "Received TaskRes with TTL %.2f "
195
- "exceeding the allowed maximum TTL %.2f.",
196
- task_res.task.ttl,
203
+ "Received Message with TTL %.2f exceeding the allowed maximum "
204
+ "TTL %.2f.",
205
+ res_metadata.ttl,
197
206
  max_allowed_ttl,
198
207
  )
199
208
  return None
200
209
 
201
210
  # Validate run_id
202
- if task_res.run_id not in self.run_ids:
203
- log(ERROR, "`run_id` is invalid")
211
+ if res_metadata.run_id != ins_metadata.run_id:
212
+ log(ERROR, "`metadata.run_id` is invalid")
204
213
  return None
205
214
 
206
- # Create task_id
207
- task_id = uuid4()
215
+ # Create message_id
216
+ message_id = uuid4()
208
217
 
209
- # Store TaskRes
210
- task_res.task_id = str(task_id)
218
+ # Store Message
219
+ # pylint: disable-next=W0212
220
+ message.metadata._message_id = str(message_id) # type: ignore
211
221
  with self.lock:
212
- self.task_res_store[task_id] = task_res
213
- self.task_ins_id_to_task_res_id[UUID(task_ins_id)] = task_id
222
+ self.message_res_store[message_id] = message
223
+ self.message_ins_id_to_message_res_id[UUID(msg_ins_id)] = message_id
214
224
 
215
- # Return the new task_id
216
- return task_id
225
+ # Return the new message_id
226
+ return message_id
217
227
 
218
- def get_task_res(self, task_ids: set[UUID]) -> list[TaskRes]:
219
- """Get TaskRes for the given TaskIns IDs."""
220
- ret: dict[UUID, TaskRes] = {}
228
+ def get_message_res(self, message_ids: set[UUID]) -> list[Message]:
229
+ """Get reply Messages for the given Message IDs."""
230
+ ret: dict[UUID, Message] = {}
221
231
 
222
232
  with self.lock:
223
233
  current = time.time()
224
234
 
225
- # Verify TaskIns IDs
226
- ret = verify_taskins_ids(
227
- inquired_taskins_ids=task_ids,
228
- found_taskins_dict=self.task_ins_store,
235
+ # Verify Messge IDs
236
+ ret = verify_message_ids(
237
+ inquired_message_ids=message_ids,
238
+ found_message_ins_dict=self.message_ins_store,
229
239
  current_time=current,
230
240
  )
231
241
 
232
- # Find all TaskRes
233
- task_res_found: list[TaskRes] = []
234
- for task_id in task_ids:
235
- # If TaskRes exists and is not delivered, add it to the list
236
- if task_res_id := self.task_ins_id_to_task_res_id.get(task_id):
237
- task_res = self.task_res_store[task_res_id]
238
- if task_res.task.delivered_at == "":
239
- task_res_found.append(task_res)
240
- tmp_ret_dict = verify_found_taskres(
241
- inquired_taskins_ids=task_ids,
242
- found_taskins_dict=self.task_ins_store,
243
- found_taskres_list=task_res_found,
242
+ # Find all reply Messages
243
+ message_res_found: list[Message] = []
244
+ for message_id in message_ids:
245
+ # If Message exists and is not delivered, add it to the list
246
+ if message_res_id := self.message_ins_id_to_message_res_id.get(
247
+ message_id
248
+ ):
249
+ message_res = self.message_res_store[message_res_id]
250
+ if message_res.metadata.delivered_at == "":
251
+ message_res_found.append(message_res)
252
+ tmp_ret_dict = verify_found_message_replies(
253
+ inquired_message_ids=message_ids,
254
+ found_message_ins_dict=self.message_ins_store,
255
+ found_message_res_list=message_res_found,
244
256
  current_time=current,
245
257
  )
246
258
  ret.update(tmp_ret_dict)
247
259
 
248
- # Mark existing TaskRes to be returned as delivered
260
+ # Mark existing reply Messages to be returned as delivered
249
261
  delivered_at = now().isoformat()
250
- for task_res in task_res_found:
251
- task_res.task.delivered_at = delivered_at
262
+ for message_res in message_res_found:
263
+ message_res.metadata.delivered_at = delivered_at
252
264
 
253
265
  return list(ret.values())
254
266
 
255
- def delete_tasks(self, task_ins_ids: set[UUID]) -> None:
256
- """Delete TaskIns/TaskRes pairs based on provided TaskIns IDs."""
257
- if not task_ins_ids:
267
+ def delete_messages(self, message_ins_ids: set[UUID]) -> None:
268
+ """Delete a Message and its reply based on provided Message IDs."""
269
+ if not message_ins_ids:
258
270
  return
259
271
 
260
272
  with self.lock:
261
- for task_id in task_ins_ids:
262
- # Delete TaskIns
263
- if task_id in self.task_ins_store:
264
- del self.task_ins_store[task_id]
265
- # Delete TaskRes
266
- if task_id in self.task_ins_id_to_task_res_id:
267
- task_res_id = self.task_ins_id_to_task_res_id.pop(task_id)
268
- del self.task_res_store[task_res_id]
269
-
270
- def get_task_ids_from_run_id(self, run_id: int) -> set[UUID]:
271
- """Get all TaskIns IDs for the given run_id."""
272
- task_id_list: set[UUID] = set()
273
+ for message_id in message_ins_ids:
274
+ # Delete Messages
275
+ if message_id in self.message_ins_store:
276
+ del self.message_ins_store[message_id]
277
+ # Delete Message replies
278
+ if message_id in self.message_ins_id_to_message_res_id:
279
+ message_res_id = self.message_ins_id_to_message_res_id.pop(
280
+ message_id
281
+ )
282
+ del self.message_res_store[message_res_id]
283
+
284
+ def get_message_ids_from_run_id(self, run_id: int) -> set[UUID]:
285
+ """Get all instruction Message IDs for the given run_id."""
286
+ message_id_list: set[UUID] = set()
273
287
  with self.lock:
274
- for task_id, task_ins in self.task_ins_store.items():
275
- if task_ins.run_id == run_id:
276
- task_id_list.add(task_id)
288
+ for message_id, message in self.message_ins_store.items():
289
+ if message.metadata.run_id == run_id:
290
+ message_id_list.add(message_id)
277
291
 
278
- return task_id_list
292
+ return message_id_list
279
293
 
280
- def num_task_ins(self) -> int:
281
- """Calculate the number of task_ins in store.
294
+ def num_message_ins(self) -> int:
295
+ """Calculate the number of instruction Messages in store.
282
296
 
283
- This includes delivered but not yet deleted task_ins.
297
+ This includes delivered but not yet deleted.
284
298
  """
285
- return len(self.task_ins_store)
299
+ return len(self.message_ins_store)
286
300
 
287
- def num_task_res(self) -> int:
288
- """Calculate the number of task_res in store.
301
+ def num_message_res(self) -> int:
302
+ """Calculate the number of reply Messages in store.
289
303
 
290
- This includes delivered but not yet deleted task_res.
304
+ This includes delivered but not yet deleted.
291
305
  """
292
- return len(self.task_res_store)
306
+ return len(self.message_res_store)
293
307
 
294
308
  def create_node(self, ping_interval: float) -> int:
295
309
  """Create, store in the link state, and return `node_id`."""
@@ -19,126 +19,113 @@ import abc
19
19
  from typing import Optional
20
20
  from uuid import UUID
21
21
 
22
- from flwr.common import Context
22
+ from flwr.common import Context, Message
23
23
  from flwr.common.record import ConfigsRecord
24
24
  from flwr.common.typing import Run, RunStatus, UserConfig
25
- from flwr.proto.task_pb2 import TaskIns, TaskRes # pylint: disable=E0611
26
25
 
27
26
 
28
27
  class LinkState(abc.ABC): # pylint: disable=R0904
29
28
  """Abstract LinkState."""
30
29
 
31
30
  @abc.abstractmethod
32
- def store_task_ins(self, task_ins: TaskIns) -> Optional[UUID]:
33
- """Store one TaskIns.
31
+ def store_message_ins(self, message: Message) -> Optional[UUID]:
32
+ """Store one Message.
34
33
 
35
34
  Usually, the ServerAppIo API calls this to schedule instructions.
36
35
 
37
- Stores the value of the `task_ins` in the link state and, if successful,
38
- returns the `task_id` (UUID) of the `task_ins`. If, for any reason,
39
- storing the `task_ins` fails, `None` is returned.
36
+ Stores the value of the `message` in the link state and, if successful,
37
+ returns the `message_id` (UUID) of the `message`. If, for any reason,
38
+ storing the `message` fails, `None` is returned.
40
39
 
41
40
  Constraints
42
41
  -----------
43
- `task_ins.task.consumer.node_id` MUST be set (not constant.DRIVER_NODE_ID)
42
+ `message.metadata.dst_node_id` MUST be set (not constant.SUPERLINK_NODE_ID)
44
43
 
45
- If `task_ins.run_id` is invalid, then
46
- storing the `task_ins` MUST fail.
44
+ If `message.metadata.run_id` is invalid, then
45
+ storing the `message` MUST fail.
47
46
  """
48
47
 
49
48
  @abc.abstractmethod
50
- def get_task_ins(self, node_id: int, limit: Optional[int]) -> list[TaskIns]:
51
- """Get TaskIns optionally filtered by node_id.
49
+ def get_message_ins(self, node_id: int, limit: Optional[int]) -> list[Message]:
50
+ """Get zero or more `Message` objects for the provided `node_id`.
52
51
 
53
52
  Usually, the Fleet API calls this for Nodes planning to work on one or more
54
- TaskIns.
53
+ Message.
55
54
 
56
55
  Constraints
57
56
  -----------
58
- Retrieve all TaskIns where
57
+ Retrieve all Message where the `message.metadata.dst_node_id` equals `node_id`.
59
58
 
60
- 1. the `task_ins.task.consumer.node_id` equals `node_id` AND
61
- 2. the `task_ins.task.delivered_at` equals `""`.
62
-
63
-
64
- If `delivered_at` MUST BE set (not `""`) otherwise the TaskIns MUST not be in
65
- the result.
66
-
67
- If `limit` is not `None`, return, at most, `limit` number of `task_ins`. If
59
+ If `limit` is not `None`, return, at most, `limit` number of `message`. If
68
60
  `limit` is set, it has to be greater zero.
69
61
  """
70
62
 
71
63
  @abc.abstractmethod
72
- def store_task_res(self, task_res: TaskRes) -> Optional[UUID]:
73
- """Store one TaskRes.
64
+ def store_message_res(self, message: Message) -> Optional[UUID]:
65
+ """Store one Message.
74
66
 
75
67
  Usually, the Fleet API calls this for Nodes returning results.
76
68
 
77
- Stores the TaskRes and, if successful, returns the `task_id` (UUID) of
78
- the `task_res`. If storing the `task_res` fails, `None` is returned.
69
+ Stores the Message and, if successful, returns the `message_id` (UUID) of
70
+ the `message`. If storing the `message` fails, `None` is returned.
79
71
 
80
72
  Constraints
81
73
  -----------
74
+ `message.metadata.dst_node_id` MUST be set (not constant.SUPERLINK_NODE_ID)
82
75
 
83
- `task_res.task.consumer.node_id` MUST be set (not constant.DRIVER_NODE_ID)
84
-
85
- If `task_res.run_id` is invalid, then
86
- storing the `task_res` MUST fail.
76
+ If `message.metadata.run_id` is invalid, then
77
+ storing the `message` MUST fail.
87
78
  """
88
79
 
89
80
  @abc.abstractmethod
90
- def get_task_res(self, task_ids: set[UUID]) -> list[TaskRes]:
91
- """Get TaskRes for the given TaskIns IDs.
81
+ def get_message_res(self, message_ids: set[UUID]) -> list[Message]:
82
+ """Get reply Messages for the given Message IDs.
92
83
 
93
84
  This method is typically called by the ServerAppIo API to obtain
94
- results (TaskRes) for previously scheduled instructions (TaskIns).
95
- For each task_id provided, this method returns one of the following responses:
85
+ results (type Message) for previously scheduled instructions (type Message).
86
+ For each message_id passed, this method returns one of the following responses:
96
87
 
97
- - An error TaskRes if the corresponding TaskIns does not exist or has expired.
98
- - An error TaskRes if the corresponding TaskRes exists but has expired.
99
- - The valid TaskRes if the TaskIns has a corresponding valid TaskRes.
100
- - Nothing if the TaskIns is still valid and waiting for a TaskRes.
88
+ - An error Message if there was no message registered with such message IDs
89
+ or has expired.
90
+ - An error Message if the reply Message exists but has expired.
91
+ - The reply Message.
92
+ - Nothing if the Message with the passed message_id is still valid and waiting
93
+ for a reply Message.
101
94
 
102
95
  Parameters
103
96
  ----------
104
- task_ids : set[UUID]
105
- A set of TaskIns IDs for which to retrieve results (TaskRes).
97
+ message_ids : set[UUID]
98
+ A set of Message IDs used to retrieve reply Messages responding to them.
106
99
 
107
100
  Returns
108
101
  -------
109
- list[TaskRes]
110
- A list of TaskRes corresponding to the given task IDs. If no
111
- TaskRes could be found for any of the task IDs, an empty list is returned.
102
+ list[Message]
103
+ A list of reply Message responding to the given message IDs or Messages
104
+ carrying an Error.
112
105
  """
113
106
 
114
107
  @abc.abstractmethod
115
- def num_task_ins(self) -> int:
116
- """Calculate the number of task_ins in store.
117
-
118
- This includes delivered but not yet deleted task_ins.
119
- """
108
+ def num_message_ins(self) -> int:
109
+ """Calculate the number of Messages awaiting a reply."""
120
110
 
121
111
  @abc.abstractmethod
122
- def num_task_res(self) -> int:
123
- """Calculate the number of task_res in store.
124
-
125
- This includes delivered but not yet deleted task_res.
126
- """
112
+ def num_message_res(self) -> int:
113
+ """Calculate the number of reply Messages in store."""
127
114
 
128
115
  @abc.abstractmethod
129
- def delete_tasks(self, task_ins_ids: set[UUID]) -> None:
130
- """Delete TaskIns/TaskRes pairs based on provided TaskIns IDs.
116
+ def delete_messages(self, message_ins_ids: set[UUID]) -> None:
117
+ """Delete a Message and its reply based on provided Message IDs.
131
118
 
132
119
  Parameters
133
120
  ----------
134
- task_ins_ids : set[UUID]
135
- A set of TaskIns IDs. For each ID in the set, the corresponding
136
- TaskIns and its associated TaskRes will be deleted.
121
+ message_ins_ids : set[UUID]
122
+ A set of Message IDs. For each ID in the set, the corresponding
123
+ Message and its associated reply Message will be deleted.
137
124
  """
138
125
 
139
126
  @abc.abstractmethod
140
- def get_task_ids_from_run_id(self, run_id: int) -> set[UUID]:
141
- """Get all TaskIns IDs for the given run_id."""
127
+ def get_message_ids_from_run_id(self, run_id: int) -> set[UUID]:
128
+ """Get all instruction Message IDs for the given run_id."""
142
129
 
143
130
  @abc.abstractmethod
144
131
  def create_node(self, ping_interval: float) -> int: