pycord icon indicating copy to clipboard operation
pycord copied to clipboard

feat(loop): add optional overlap support to allow concurrent loop executions

Open Lumabots opened this issue 8 months ago • 14 comments

Summary

Information

  • [ ] This PR fixes an issue.
  • [x] This PR adds something new (e.g. new method or parameters).
  • [ ] This PR is a breaking change (e.g. methods or parameters removed/renamed).
  • [ ] This PR is not a code change (e.g. documentation, README, typehinting, examples, ...).

Checklist

  • [x] I have searched the open pull requests for duplicates.
  • [x] If code changes were made then they have been tested.
    • [x] I have updated the documentation to reflect the changes.
  • [x] If type: ignore comments were used, a comment is also left explaining why.
  • [x] I have updated the changelog to include these changes.

Lumabots avatar Apr 30 '25 19:04 Lumabots

sorry i renamed the branch and it deleted the other one

Lumabots avatar Apr 30 '25 19:04 Lumabots

We should probably add an additional parameter for limiting the number of active tasks

maybe: def init(self, ..., overlap: bool | int = True):

If overlap is:

True: allow overlapping tasks with no limit (default).

False: do not allow overlapping (wait for task to finish).

An int: allow overlapping up to n concurrent tasks.

Lumabots avatar May 01 '25 08:05 Lumabots

so i did some change but i'll debug that tonight + if someone can tell me about my implementation in case overlap if false, should i stick with await coro ? or else its good like so

Lumabots avatar May 01 '25 08:05 Lumabots

not ready for review

Lumabots avatar May 01 '25 15:05 Lumabots

well my new fix breaks a bit the current_loop number, if anyone has an idea Screenshot 2025-05-01 at 16 48 18

Lumabots avatar May 01 '25 15:05 Lumabots

    @tasks.loop(seconds=5, overlap=2)
    async def test_loop(self):
        logger.debug(
            f"test loop {self.test_loop.current_loop}, Next loop {self.test_loop.next_iteration}, tasks {self.test_loop.get_task()}"
        )
        await asyncio.sleep(15)
        logger.debug(f"test loop done {self.test_loop.current_loop}")

Lumabots avatar May 01 '25 15:05 Lumabots

well my new fix breaks a bit the current_loop number, if anyone has an idea Screenshot 2025-05-01 at 16 48 18

probably because all the loops have the same state, so after 3 loops run they'll all thing they're on 3

plun1331 avatar May 01 '25 16:05 plun1331

i mean i dont really think thats an issue, since its overlapping there is no way to keep the current loop inside the same thing, and if i do make that for inside the loop the current loop doesnt update then in every other usage than the loop it itself the number will not be accurate.

well my new fix breaks a bit the current_loop number, if anyone has an idea Screenshot 2025-05-01 at 16 48 18

probably because all the loops have the same state, so after 3 loops run they'll all thing they're on 3

yep ik that, but im working on something for inside the loop we do have the same current loop and outside we have the general index. If not needed i can just let this behavour

Lumabots avatar May 01 '25 16:05 Lumabots

I think we just change the docs to specify that it represents the number of loops that have been started

plun1331 avatar May 01 '25 16:05 plun1331

so i did that inside the loop it continue to give the same one, but if you use another command it return the real one, what do you think about that

Lumabots avatar May 01 '25 16:05 Lumabots

if you can get that to work then that would be fine

plun1331 avatar May 01 '25 16:05 plun1331

Screenshot 2025-05-01 at 17 22 47 so this is the result inside the loop for @tasks.loop(seconds=5, overlap=True) async def test_loop(self): logger.debug( f"test loop {self.test_loop.current_loop}, Next loop {self.test_loop.next_iteration}, tasks {self.test_loop.get_task()}" ) await asyncio.sleep(15) logger.debug(f"test loop done {self.test_loop.current_loop}")

but inside my command if i do await ctx.respond(f"test, {self.test_loop.current_loop}")

it will return the number of loop totals like before

Lumabots avatar May 01 '25 16:05 Lumabots

Oh, one extra thing, tasks should be removed from _tasks after they complete (otherwise the list will just grow infinitely)

is this enough ?

task = asyncio.create_task(
    (
        self.coro(*args, **kwargs)
        if self.overlap is True
        else run_with_semaphore()
    ),
    name=f"pycord-loop-{self.coro.__name__}-{self._current_loop}",
)
task.add_done_callback(self._tasks.remove)
self._tasks.append(task)

Lumabots avatar May 01 '25 16:05 Lumabots

should be ready for review

Lumabots avatar May 01 '25 16:05 Lumabots

Merge conflicts

Lulalaby avatar Aug 02 '25 03:08 Lulalaby

fixed

Lumabots avatar Aug 02 '25 10:08 Lumabots

Could that potentially clutch with #2645?

Not anymore

Lumabots avatar Sep 07 '25 18:09 Lumabots

This could use a little example, either in the docs or in the directory. As it's asked for once in a while, and an example could help with explaining it in detail.

Soheab avatar Sep 19 '25 08:09 Soheab

This could use a little example, either in the docs or in the directory. As it's asked for once in a while, and an example could help with explaining it in detail.

For loop in general or mainly for overlap ?

Lumabots avatar Sep 19 '25 13:09 Lumabots

This could use a little example, either in the docs or in the directory. As it's asked for once in a while, and an example could help with explaining it in detail.

For loop in general or mainly for overlap ?

The latter. Like one that shows a common use case and explains it a little bit.

Soheab avatar Sep 22 '25 07:09 Soheab

@Pycord-Development/maintain-discord-api pls thx :)

Paillat-dev avatar Oct 11 '25 11:10 Paillat-dev