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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cancel pending tasks #729

Merged
merged 5 commits into from
Dec 21, 2018
Merged

Cancel pending tasks #729

merged 5 commits into from
Dec 21, 2018

Conversation

FabioRosado
Copy link
Member

Description

This is not the right way that the issue 723 suggests we should approach this issue. But I was unsure how to get running tasks because asyncio.Task.all_tasks seems to return all tasks not only pending but also the ones that have been set as done or finished.

I tried to search how to get only the pending tasks but couldn't figure out the best way to do this, since I couldn't figure out I couldn't create a condition to make opsdroid sleep for x amount of seconds before cancelling the task.

This solution does cancel the task but I'm not sure if this is the best way to do things like I said before. Would like to get some more feedback on how to approach the issue in a better way 馃憤

Fixes #723

Status

READY | UNDER DEVELOPMENT | ON HOLD

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.

  • Tox passes
  • Ran opsdroid, killed it and no exception was raised

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@codecov
Copy link

codecov bot commented Nov 8, 2018

Codecov Report

Merging #729 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master   #729   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files          28     28           
  Lines        1851   1857    +6     
=====================================
+ Hits         1851   1857    +6
Impacted Files Coverage 螖
opsdroid/core.py 100% <100%> (酶) 猬嗭笍

Continue to review full report at Codecov.

Legend - Click here to learn more
螖 = absolute <relative> (impact), 酶 = not affected, ? = missing data
Powered by Codecov. Last update ea1ed8a...b9ca23a. Read the comment docs.

@jacobtomlinson
Copy link
Member

Yeah I also struggled with this. We need to cancel all tasks after a certain timeout (maybe 30 seconds), however this function is being called from within a task so we need to ignore that one. Sleeping for 30 seconds isn't great either as it would keep the thread open.

I think we should be counting the number of running tasks (not including the current task) every 0.1 seconds. If we get to 300 checks then they should be cancelled, if they all complete on their own then we should break out of the loop.

As you said counting the number of running tasks is tricky though. Might be worth a stack overflow question?

@stale
Copy link

stale bot commented Nov 22, 2018

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Nov 22, 2018
@FabioRosado
Copy link
Member Author

I was giving some thought about this issue and started looking into how other projects seem to close/cancel tasks, do you think is it possible to do something like in the aioslacker?

It seems they are adding all tasks(ensure_future creates tasks right?) into a set, with lines 103-105

fut = ensure_future(coro, loop=self.loop)

self.futs.add(fut)

Then when we try to close the slacker the method close uses:

        if self.futs:
            yield from asyncio.gather(*self.futs, loop=self.loop)

        yield from self.session.close()

Perhaps we could add the connector.listen method (this is where most of the issues happen) into a sort of set/list and on the disconnect just disconnect that task?

Another thing we could do is change the connector.disconnect method from being passed to raise NotImplementedError and then when we try to disconnect, if that exception is raised we can just cancel that task?

@stale stale bot removed the stale label Nov 25, 2018
@jacobtomlinson
Copy link
Member

Yeah that all sounds good.

The only other thing to consider is that if someone's skill enters an infinite (or at least long running) loop that task will need to be cancelled too. Perhaps we should track called skill tasks as well.

Copy link
Contributor

@petri petri left a comment

Choose a reason for hiding this comment

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

You can just nicely cancel the tasks that are not yet done like this:

        # The extensions have been given a chance to clean up
        # gracefully in disconnect(). We can now cancel what we started.
        pending = asyncio.Task.all_tasks()
        for p in list(pending):
            if not p.done() and p is not asyncio.current_task():
                p.cancel()

@jacobtomlinson
Copy link
Member

That was my original plan @petri, however the function is called within a task and it cancels itself. I haven't managed to find a way of not cancelling itself.

@petri
Copy link
Contributor

petri commented Dec 5, 2018

@jacobtomlinson recheck the code above. It's not canceling itself due to checking for p is not asyncio.current_task().

@jacobtomlinson
Copy link
Member

Totally missed that! Nice!

@jacobtomlinson
Copy link
Member

@FabioRosado could you please update this?

@FabioRosado
Copy link
Member Author

Just updated the PR, we will probably have an issue with testing as I need to test for task.cancel() but I haven't managed to figure out how to do this properly. I attempted to mock this method in order to see if it was called, but that didn't work out

@FabioRosado
Copy link
Member Author

So in the end testing this was way easier than I was thinking. Should I merge this now @jacobtomlinson ?

@FabioRosado FabioRosado merged commit 8ec7487 into opsdroid:master Dec 21, 2018
@FabioRosado FabioRosado deleted the cancel-tasks branch December 21, 2018 20:35
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.

Application hangs on kill if connector doesn't disconnect
3 participants