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

Fix race condition #1039

Merged
merged 14 commits into from Apr 17, 2022
Merged

Conversation

Mihitoko
Copy link
Contributor

Summary

Fixes a race condition in interactions.py when two responses are made at the same time.
This PR fixes #963

Checklist

  • If code changes were made then they have been tested.
    • I have updated the documentation to reflect the changes.
  • If type: ignore comments were used, a comment is also left explaining why
  • This PR fixes an issue.
  • 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, ...)

@krittick
Copy link
Contributor

krittick commented Feb 17, 2022

I feel like automatically sending a followup when an exception is encountered isn't the right way to handle this. I also don't think this is an issue with the library itself, but rather just how asyncio.create_task() works.

Using the same example in the original issue but replacing the double asyncio.create_task(respond()) with double await respond() does not cause the issue.

@Mihitoko
Copy link
Contributor Author

I feel like automatically sending a followup when an exception is encountered isn't the right way to handle this. I also don't think this is an issue with the library itself, but rather just how asyncio.create_task() works.

Sending a followup when the interaction is already responded was also implemented before i made changes.
The exeption catch only ensures that we followup when a response was made while we executed cureent response.

Using the same example in the original issue but replacing the double asyncio.create_task(respond()) with double await respond() does not cause the issue.

It was just an example.
This happens a lot when you implement auto defering by yourself.
And the task to defer the interaction executes at the same time as the response.
This issue is pretty niche but a race condition that can lead to unexpected behavior should still be adressed in my opinion.

@krittick
Copy link
Contributor

Can you provide an example that doesn't use create_task() then?

@Mihitoko
Copy link
Contributor Author

Can you provide an example that doesn't use create_task() then?

I think you understood me wrong.
I know its that behavior of create task that enables this exception.
If you await the task it will not happen.
So no i cant

My point was that there a good reasons for putting a response in a task and not awaiting it.
So from my point of view we should ensure that no race condition is happening.

@BadWolf1023
Copy link

BadWolf1023 commented Feb 17, 2022

Can you provide an example that doesn't use create_task() then?

Why? That’s a basic usage of asyncio. But for the sake of the question, you could replicate this behavior without explicitly using create_task in your specific code in several different ways. For example, if someone ran a slash command and your slash command code made a reference to another ApplicationContext, calling .respond() on that object.

The problem is here:
3dcd834#diff-d40bf8033607a75e12d53f161d4983e9c1dff8eaa62eba83e947874d7812f5fdL792
When you call await in this line, you allow the asyncio loop to run a different scheduled (or awaited) coroutine which may also call .respond on that same object which could finish before this line’s coroutine is run by the asyncio loop.

@BadWolf1023 BadWolf1023 mentioned this pull request Feb 18, 2022
3 tasks
@Mihitoko
Copy link
Contributor Author

In my opinion catching the InteractionResponded exception is the best way to go here.
There is nothing hacky about catching an exception that is expected to be risen.

A soloution that might also work is

Add this method to InteractionResponse

# Not sure about the name tho, maybe change it
async def respond_dynamic(self, *args, **kwargs):
    try:
        await self.send_message(*args, **kwargs)
    except InteractionResponded:
        # get followup webhook from parent
        await self._parent.followup.send(*args, **kwargs)

This still invoves the error catch but is a lot cleaner then my aproach catching the error in the context object.

ApplicationContext

Just retrun the method above in ApplicationContext.respond

What are your thoughts about this aproach ?

@Vondyy
Copy link

Vondyy commented Feb 19, 2022

Regarding #1041 I did download Mihitoko fork and it still happens, so my issue lies elsewhere I'm pre sure. So, don't think application did not respond is not tied to this.

@Mihitoko
Copy link
Contributor Author

Regarding #1041 I did download Mihitoko fork and it still happens, so my issue lies elsewhere I'm pre sure. So, don't think application did not respond is not tied to this.

Did you download fix_race_condtition branch?
The fix is not on master on my fork.
Although Im not sure if that's really the problem in your issue.

@Vondyy
Copy link

Vondyy commented Feb 19, 2022

I used pip install git+https://github.com/Mihitoko/pycord.git and I still get the issue. I made sure I did pip uninstall py-cord first

@VincentRPS
Copy link
Member

I used pip install git+https://github.com/Mihitoko/pycord.git and I still get the issue. I made sure I did pip uninstall py-cord first

You need to add @fix_race_condition to that link.

@BobDotCom
Copy link
Member

Merge conflicts here, please resolve.

@Mihitoko
Copy link
Contributor Author

Mihitoko commented Mar 4, 2022

Merge conflicts here, please resolve.

Done.

Copy link
Contributor

@TurnrDev TurnrDev left a comment

Choose a reason for hiding this comment

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

You forgot a return and you might as well refactor respond to just be an async function. It being a property was always a mistake

@krittick
Copy link
Contributor

You forgot a return and you might as well refactor respond to just be an async function. It being a property was always a mistake

The core devs have been discussing this internally and this is actually part of our planned approach to tackle this.

Lulalaby and others added 2 commits April 3, 2022 21:44
Copy link
Member

@Dorukyum Dorukyum left a comment

Choose a reason for hiding this comment

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

These suggestions should turn this into an async function.

discord/commands/context.py Outdated Show resolved Hide resolved
discord/commands/context.py Outdated Show resolved Hide resolved
Lulalaby and others added 2 commits April 9, 2022 20:33
Co-authored-by: Dorukyum <53639936+Dorukyum@users.noreply.github.com>
Co-authored-by: Dorukyum <53639936+Dorukyum@users.noreply.github.com>
krittick
krittick previously approved these changes Apr 16, 2022
Copy link
Contributor

@krittick krittick left a comment

Choose a reason for hiding this comment

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

LGTM now

@krittick krittick enabled auto-merge (squash) April 16, 2022 19:51
Copy link
Member

@Dorukyum Dorukyum left a comment

Choose a reason for hiding this comment

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

Minor documentation/styling changes

discord/interactions.py Outdated Show resolved Hide resolved
discord/interactions.py Outdated Show resolved Hide resolved
discord/interactions.py Outdated Show resolved Hide resolved
discord/interactions.py Outdated Show resolved Hide resolved
Co-authored-by: Dorukyum <53639936+Dorukyum@users.noreply.github.com>
Lulalaby and others added 3 commits April 18, 2022 00:01
Co-authored-by: Dorukyum <53639936+Dorukyum@users.noreply.github.com>
Co-authored-by: Dorukyum <53639936+Dorukyum@users.noreply.github.com>
Co-authored-by: Dorukyum <53639936+Dorukyum@users.noreply.github.com>
@krittick krittick merged commit 8e904b3 into Pycord-Development:master Apr 17, 2022
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.

Race condition in InteractionResponse
9 participants