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

replace requests with httpx and factor out clients #1574

Merged
merged 3 commits into from
Mar 29, 2024
Merged

Conversation

technillogue
Copy link
Contributor

@technillogue technillogue commented Mar 12, 2024

this is a step towards merging #1530 into the async release channel. it's a repeat of #1508 without actually adding concurrency or the less runner stuff from #1499. hopefully the remainder of #1530 is easier to review once this is done.

as I recall, the main reason we couldn't release async runner was that cog.Path/File using requests would block the event loop and prevent work from advancing. because of that, these are probably the first changes that need to be released into mainline cog to proceed.

  • input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
  • although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
  • there's a kind of ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
  • the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
  • the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

@technillogue technillogue force-pushed the syl/httpx-only branch 2 times, most recently from b4e958c to 224e593 Compare March 12, 2024 23:50
@technillogue technillogue requested a review from a team March 13, 2024 20:02
.github/workflows/ci.yaml Outdated Show resolved Hide resolved


def httpx_webhook_client() -> httpx.AsyncClient:
return httpx.AsyncClient(headers=webhook_headers(), follow_redirects=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like we need to opt-in to enable HTTP/2

Suggested change
return httpx.AsyncClient(headers=webhook_headers(), follow_redirects=True)
return httpx.AsyncClient(headers=webhook_headers(), follow_redirects=True, http2=True)

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 will note there is likely no benefit to using http2 for director, it only really matters for file downloads and maybe uploads from the internet

python/cog/server/clients.py Show resolved Hide resolved
self.webhook_client = httpx_webhook_client()
self.retry_webhook_client = httpx_retry_client()
self.file_client = httpx_file_client()
self.download_client = httpx.AsyncClient(follow_redirects=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

Extract this into a helper method like the others?

Also, initialize with http2=True

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's one line, all the other ones have more involved configuration

import requests
import responses
from cog.schema import WebhookEvent
from cog.server.webhook import webhook_caller, webhook_caller_filtered

#from cog.server.webhook import webhook_caller, webhook_caller_filtered
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
#from cog.server.webhook import webhook_caller, webhook_caller_filtered


class URLFile(io.IOBase):
"""
URLFile is a proxy object for a :class:`urllib3.response.HTTPResponse`
object that is created lazily. It's a file-like object constructed from a
URL that can survive pickling/unpickling.

This is the only place Cog uses requests
Copy link
Contributor

Choose a reason for hiding this comment

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

What would it take to get rid of requests outright?

Would something like this work?

@property
def __wrapped__(self) -> Any:
    try:
        return object.__getattribute__(self, "__target__")
    except AttributeError:
        url = object.__getattribute__(self, "__url__")
        with httpx.stream("GET", url) as resp:
            resp.raise_for_status()
            resp.raw.decode_content = True
            object.__setattr__(self, "__target__", resp.raw)
            return resp.raw

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 think that would work, I just didn't bother yet because nobody anywhere uses File and this solution is still a little unsatisfying (it would block the event loop). I also suspect requests is always installed because pip depends on it.

Copy link
Contributor

Choose a reason for hiding this comment

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

requests is always installed because pip depends on it

🤨

Maybe that's no longer the case? According to this, pip has no external dependencies.

Not urgent or blocking, but it'd be nice to make a clean break.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh yeah they vendored it in a while ago, I forgot. and I'm mistaken, python:3.11-slim doesn't have requests by default.

I'd still lean towards leaving it obviously broken rather then seeming okay but actually blocking the event loop. good ways to do this include subprocesses with a pipe, some kind of thread nonsense or a hypothetical pget-py binding

@@ -24,7 +24,7 @@ def test_run_with_secret(tmpdir_factory):
with open(tmpdir / "cog.yaml", "w") as f:
cog_yaml = """
build:
python_version: "3.8"
python_version: "3.9"
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason why this is targeting 3.9 instead of 3.8?

technillogue and others added 3 commits March 28, 2024 16:57
Signed-off-by: technillogue <technillogue@gmail.com>
Co-authored-by: Mattt <mattt@replicate.com>
Signed-off-by: technillogue <wisepoison@gmail.com>
Signed-off-by: technillogue <technillogue@gmail.com>
Signed-off-by: technillogue <technillogue@gmail.com>
@technillogue technillogue merged commit 7ee96ba into async Mar 29, 2024
10 checks passed
@technillogue technillogue deleted the syl/httpx-only branch March 29, 2024 05:22
technillogue added a commit that referenced this pull request May 8, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Signed-off-by: technillogue <technillogue@gmail.com>
Co-authored-by: Mattt <mattt@replicate.com>
Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request May 8, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Signed-off-by: technillogue <technillogue@gmail.com>
Co-authored-by: Mattt <mattt@replicate.com>
Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request May 8, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Signed-off-by: technillogue <technillogue@gmail.com>
Co-authored-by: Mattt <mattt@replicate.com>
Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jun 19, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jun 19, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jun 19, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jun 19, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jul 18, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
mattt pushed a commit that referenced this pull request Jul 18, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
mattt pushed a commit that referenced this pull request Jul 19, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jul 24, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jul 24, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
@technillogue technillogue mentioned this pull request Jul 24, 2024
technillogue added a commit that referenced this pull request Jul 24, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jul 25, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jul 25, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
technillogue added a commit that referenced this pull request Jul 26, 2024
* input downloads, output uploads, and webhooks are now handled by ClientManager, which persists for the lifetime of runner, allowing us to reuse connections, which may significantly help with large uploads.
* although I was originally going to drop output_file_prefix, it's not actually hard to maintain. the behavior is changed now and objects are uploaded as soon as they're outputted rather than after the prediction is completed.
* there's an ugly hack with uploading an empty body to get the redirect instead of making api time out from trying to upload an 140GB file. that can be fixed by implemented an MPU endpoint and/or a "fetch upload url" endpoint.
* the behavior of the non-indempotent endpoint is changed; the id is now randomly generated if it's not provided in the body. this isn't strictly required for this change alone, but is hard to carve out.
* the behavior of Path is changed significantly. see https://www.notion.so/replicate/Cog-Setup-Path-Problem-2fc41d40bcaf47579ccd8b2f4c71ee24

Co-authored-by: Mattt <mattt@replicate.com>

* format
* stick a %s on line 190 clients.py (#1707)
* local upload server can be called cluster.local in addition to .internal (#1714)

Signed-off-by: technillogue <technillogue@gmail.com>
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.

2 participants