@@ -155,7 +155,56 @@ async def _run(self) -> None:
155155## Implementing an Actor
156156
157157To implement an actor, you must inherit from the [`Actor`][frequenz.sdk.actor.Actor]
158- class and implement the abstract [`_run()`][_run] method.
158+ class and implement an *initializer* and the abstract [`_run()`][_run] method.
159+
160+ ### Initialization
161+
162+ The [initializer][object.__init__] is called when the actor is created. The
163+ [`Actor`][frequenz.sdk.actor.Actor] class initializer
164+ ([`__init__`][frequenz.sdk.actor.Actor.__init__]) should be always called first in the
165+ class we are implementing to make sure actors are properly initialized.
166+
167+ The [`Actor.__init__()`][frequenz.sdk.actor.Actor.__init__] takes one optional argument,
168+ a [`name`][frequenz.sdk.actor.Actor.name] that will be used to identify the actor in
169+ logs. If no name is provided, a default name will be generated, but it is recommended
170+ that [`Actor`][frequenz.sdk.actor.Actor] subclasses can also receive a name as an
171+ argument to make it easier to identify individual instances in logs more easily.
172+
173+ The actor initializer normally also accepts as arguments the input channels receivers
174+ and output channels senders that will be used for communication. These channels should
175+ be created outside the actor and passed to it as arguments to ensure actors can be
176+ composed easily.
177+
178+ ???+ example "Example echo actor"
179+
180+ ```python
181+ from frequenz.channels import Receiver, Sender
182+ from frequenz.sdk.actor import Actor
183+
184+ class EchoActor(Actor): # (1)!
185+ def __init__(
186+ self,
187+ input: Receiver[int], # (2)!
188+ output: Sender[int], # (3)!
189+ name: str | None = None, # (4)!
190+ ) -> None:
191+ super().__init__(name=name) # (5)!
192+ self._input: Receiver[int] = input # (6)!
193+ self._output: Sender[int] = output # (7)!
194+ ```
195+
196+ 1. We define a new actor class called `EchoActor` that inherits from
197+ [`Actor`][frequenz.sdk.actor.Actor].
198+
199+ 2. We accept an `input` argument that will be used to receive messages from
200+ a channel.
201+ 3. We accept an `output` argument that will be used to send messages to a channel.
202+ 4. We accept an optional `name` argument that will be used to identify the actor in
203+ logs.
204+ 5. We call [`Actor.__init__()`][frequenz.sdk.actor.Actor.__init__] to make sure the
205+ actor is properly initialized.
206+ 6. We store the `input` argument in a *private* instance variable to use it later.
207+ 7. We store the `output` argument in a *private* instance variable to use it later.
159208
160209### The `_run()` Method
161210
@@ -168,6 +217,32 @@ class and implement the abstract [`_run()`][_run] method.
168217([receivers][frequenz.channels.Receiver]), processing them and sending the results to
169218other channels ([senders][frequenz.channels.Sender]).
170219
220+ ???+ example "Example echo actor"
221+
222+ ```python
223+ from frequenz.channels import Receiver, Sender
224+ from frequenz.sdk.actor import Actor
225+
226+ class EchoActor(Actor):
227+ def __init__(
228+ self,
229+ input: Receiver[int],
230+ output: Sender[int],
231+ name: str | None = None,
232+ ) -> None:
233+ super().__init__(name=name)
234+ self._input: Receiver[int] = input
235+ self._output: Sender[int] = output
236+
237+ async def _run(self) -> None: # (1)!
238+ async for msg in self._input: # (2)!
239+ await self._output.send(msg) # (3)!
240+ ```
241+
242+ 1. We implement the abstract [`_run()`][_run] method.
243+ 2. We receive messages from the `input` channel one by one.
244+ 3. We send the received message to the `output` channel.
245+
171246### Stopping
172247
173248By default, the [`stop()`][frequenz.sdk.actor.Actor.stop] method will call the
@@ -270,8 +345,9 @@ def __init__(
270345 self,
271346 receiver: Receiver[str],
272347 output: Sender[str],
348+ name: str | None = None,
273349 ) -> None:
274- super().__init__()
350+ super().__init__(name=name )
275351 self._receiver = receiver
276352 self._output = output
277353
@@ -285,8 +361,9 @@ def __init__(
285361 self,
286362 receiver: Receiver[str],
287363 output: Sender[str],
364+ name: str | None = None,
288365 ) -> None:
289- super().__init__()
366+ super().__init__(name=name )
290367 self._receiver = receiver
291368 self._output = output
292369
@@ -305,8 +382,8 @@ async def main() -> None: # (2)!
305382 output_receiver = output_channel.new_receiver()
306383
307384 async with ( # (5)!
308- Actor1(input_channel.new_receiver(), middle_channel.new_sender()),
309- Actor2(middle_channel.new_receiver(), output_channel.new_sender()),
385+ Actor1(input_channel.new_receiver(), middle_channel.new_sender(), "actor1" ),
386+ Actor2(middle_channel.new_receiver(), output_channel.new_sender(), "actor1" ),
310387 ):
311388 await input_sender.send("Hello") # (6)!
312389 msg = await output_receiver.receive() # (7)!
@@ -388,8 +465,9 @@ def __init__(
388465 receiver_1: Receiver[bool],
389466 receiver_2: Receiver[bool],
390467 output: Sender[bool],
468+ name: str | None = None,
391469 ) -> None:
392- super().__init__()
470+ super().__init__(name=name )
393471 self._receiver_1 = receiver_1
394472 self._receiver_2 = receiver_2
395473 self._output = output
@@ -421,6 +499,7 @@ async def _run(self) -> None: # (2)!
421499 input_channel_1.new_receiver(),
422500 input_channel_2.new_receiver(),
423501 echo_channel.new_sender(),
502+ "echo-actor",
424503)
425504
426505echo_receiver = echo_channel.new_receiver() # (5)!
0 commit comments