Skip to content

Conversation

@Marenz
Copy link
Contributor

@Marenz Marenz commented Jun 12, 2025

No description provided.

Copilot AI review requested due to automatic review settings June 12, 2025 18:37
@Marenz Marenz requested a review from a team as a code owner June 12, 2025 18:37
@github-actions github-actions bot added the part:dispatcher Affects the high-level dispatcher interface label Jun 12, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a new override for the stop() method in the background service to ensure that a timer is properly stopped before proceeding with the shutdown process.

  • Introduces an overridden stop() method that stops the _next_event_timer
  • Calls the parent class's stop() method after stopping the timer
Comments suppressed due to low confidence (1)

src/frequenz/dispatch/_bg_service.py:223

  • [nitpick] Consider expanding the docstring for the stop() method to clarify that stopping _next_event_timer is crucial for preventing potential resource leaks during shutdown.
@override

@Marenz
Copy link
Contributor Author

Marenz commented Jun 12, 2025

Interesting that the CI fails when I add the stop method (one test)...

@override
async def stop(self, msg: str | None = None) -> None:
"""Stop the background service."""
self._next_event_timer.stop()
Copy link
Contributor

Choose a reason for hiding this comment

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

We are probably going to deprecate .stop() as it was something specific for Timer, but now we have close() in the Receiver interface, so it might be more future-proof to use close().

Also since this is a background service, it is better to put the close() in cancel() instead of stop(), otherwise if you d.cancel(); await d the timer won't be closed.

Finally this might be more complicated than you thought, at least we had issues in some other places where now you start getting a ReceiverStoppedError/StopAsyncIteration exception in the run you might need to start catching. Maybe this is a more actor-specific issue because of the auto-restart and is not really an issue for pure background services though, but just something to have in mind.

@Marenz Marenz added the cmd:skip-release-notes It is not necessary to update release notes for this PR label Jun 16, 2025
@Marenz Marenz requested a review from llucax June 16, 2025 09:22
@Marenz
Copy link
Contributor Author

Marenz commented Jun 16, 2025

Changed to close() and added reset() in start to fix failing test and also because it's correct

@Marenz Marenz enabled auto-merge June 16, 2025 09:24
Copy link
Contributor

@llucax llucax left a comment

Choose a reason for hiding this comment

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

I'm starting to think what's really more correct is:

    async def _run(self) -> None:
        with closing(Timer(
            timedelta(seconds=100), SkipMissedAndResync()
        ) as next_event_timer:
            ...

This way you don't need to mess with start/stop/cancel, you don't need auto_start=False, and you have guaranteed cleanup. Do you see any problems with this?

BTW, probably the timer's period should be a constructor argument with 100 seconds just as a default.

@Marenz
Copy link
Contributor Author

Marenz commented Jun 16, 2025

BTW, probably the timer's period should be a constructor argument with 100 seconds just as a default.

Why? It's overwritten in update_timer() for pretty much any activity

@github-actions github-actions bot added the part:tests Affects the unit, integration and performance (benchmarks) tests label Jun 16, 2025
@llucax
Copy link
Contributor

llucax commented Jun 16, 2025

We talked already via DM but just for the records, it is basically to ensure proper cleanup, and to tie the lifetime of the timer to the lifetime of the task/run. Maybe is not worth it as we have other instance variables that would also make sense to move to run, but that is too much work and if only do it for the timer, we might end up in the middle of 2 worlds, so I leave it up to you.

Copy link
Contributor

@llucax llucax left a comment

Choose a reason for hiding this comment

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

Not approving because of the comment and auto-merge but feel free to self-merge if you address it.

raise RuntimeError("Dispatch service not started")

(task,) = self._tasks
if task.done():
Copy link
Contributor

Choose a reason for hiding this comment

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

self.is_running?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I swear, I was looking for it

@Marenz Marenz disabled auto-merge June 17, 2025 07:19
@Marenz Marenz merged commit a3332ea into frequenz-floss:v0.x.x Jun 17, 2025
5 checks passed
@Marenz Marenz deleted the stop branch June 17, 2025 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cmd:skip-release-notes It is not necessary to update release notes for this PR part:dispatcher Affects the high-level dispatcher interface part:tests Affects the unit, integration and performance (benchmarks) tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants