Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use _write_async_message for sensor updates #100

Merged
merged 2 commits into from
Sep 8, 2024

Conversation

bmerry
Copy link
Contributor

@bmerry bmerry commented Sep 5, 2024

Clients that don't keep up with sensor updates will now be disconnected,
instead of causing the server to use an ever-increasing amount of RAM.

This required some unintuitive changes to keep mypy happy, due to
python/mypy#17723.

Clients that don't keep up with sensor updates will now be disconnected,
instead of causing the server to use an ever-increasing amount of RAM.

This required some unintuitive changes to keep mypy happy, due to
python/mypy#17723.
@coveralls
Copy link

Coverage Status

coverage: 92.721%. remained the same
when pulling 0f3a602 on NGC-1440-sensor-update-disconnect
into a2a268b on master.

Copy link
Contributor

@amishatishpatel amishatishpatel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat!

Comment on lines +229 to +232
# list() is to avoid errors if the set is modified during iteration.
for classic_observer in list(self._classic_observers):
classic_observer(self, reading)
for delta_observer in self._delta_observers:
for delta_observer in list(self._delta_observers):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted. Although, how does it do that? By wrapping in list(..), does it e.g. 'keep the cast copy in place until we're done using it'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

list makes a copy. So we're iterating over a copy (which won't change) rather than the original (which might).

@@ -99,7 +101,7 @@ def sensor_update(self, s: sensor.Sensor, reading: sensor.Reading) -> None:
msg = core.Message.inform(
"sensor-status", reading.timestamp, 1, s.name, reading.status, reading.value
)
self.write_message(msg)
self.owner._write_async_message(self, msg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this sounded familiar. I once had to server.mass_inform, I see it uses this under the hood.

@@ -64,6 +64,8 @@
class ClientConnection(connection.Connection):
"""Server's view of the connection from a single client."""

owner: "DeviceServer"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To get a bit pedantic/academic, your reasoning for making this a class attribute rather than an instance attribute?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is an instance attribute. If it was a class attribute, it would be declared

    owner: ClassVar["DeviceServer"]

I added this to refine the type information: from the base class, typing tools would only know that it is a _ConnectionOwner[ClientConnection].

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting.

Comment on lines +645 to +660
async def test_slow_client_sensor(
server: DummyServer, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
) -> None:
server.max_backlog = 32768
big_str = b"x" * 200000
writer.write(b"?sensor-sampling str-sensor auto\n")
await check_reply(
reader,
[
re.compile(rb"^#sensor-status [0-9.]+ 1 str-sensor unknown \\@"),
b"!sensor-sampling ok str-sensor auto\n",
],
)
assert len(server._connections) == 1
server.sensors["str-sensor"].value = big_str
assert len(server._connections) == 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice.

@bmerry
Copy link
Contributor Author

bmerry commented Sep 8, 2024

I'm going to merge for now, but I think I still want to tweak things so that the initial set of sensor updates that occur when issuing ?sensor-sampling don't trigger this behaviour (since bulk subscription can dump a lot into the write transport in one go).

@bmerry bmerry merged commit 64f3697 into master Sep 8, 2024
21 of 22 checks passed
@bmerry bmerry deleted the NGC-1440-sensor-update-disconnect branch September 8, 2024 06:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants