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

Alan picks an HTTP library #95

Closed
2 of 4 tasks
rylev opened this issue Mar 26, 2021 · 16 comments · Fixed by #111
Closed
2 of 4 tasks

Alan picks an HTTP library #95

rylev opened this issue Mar 26, 2021 · 16 comments · Fixed by #111
Labels
good first issue Good for newcomers help wanted Extra attention is needed status-quo-story-ideas "Status quo" user story ideas

Comments

@rylev
Copy link
Member

rylev commented Mar 26, 2021

Brief summary

Alan is building a simple library for interacting with his favorite movie tracking app "numbersquard". Numbesquard exposes their data over a restful API. Alan, new to Rust, searches for an HTTP library and quickly gets sucked into long debates about async/sync IO, Surf vs reqwest vs curl, tokio vs async-standard, etc. Alan is so filled with doubt that he doesn't even write a line of code.

Optional details

  • Which character(s) would be the best fit and why?
    • Alan: the experienced "GC'd language" developer, new to Rust
      • Alan is probably best since picking an HTTP library in many languages is a non-choice, you just use the built-in standard library implementation.
    • Grace: the systems programming expert, new to Rust
    • Niklaus: new programmer from an unconventional background
    • Barbara: the experienced Rust developer
      *Which project(s) would be the best fit and why?
    • While SLOW might work, I think it's important that the project not feel like it actually has much to do with networking. This library helps people track their movie watching on the numbersquard platform. Concerns like async/sync, which HTTP library to use, etc. are very much implementation details and actually shouldn't really matter. Alan just wants to build the library and not care.
  • What are the key points or morals to emphasize?
    • HTTP is so ubiquitous that it's often a small and insignificant implementation detail of many libraries that on the surface have little to nothing to do with networking, I/O, etc. However, choosing which HTTP implementation to use, requires a HUGE amount of understanding of the state of the Rust async ecosystem.

This story is similar in many ways to #54, #49, and #45, but HTTP is so common and this particular situation so relevant to so many projects that I think it needs to be called out explicitly.

@rylev rylev added good first issue Good for newcomers help wanted Extra attention is needed status-quo-story-ideas "Status quo" user story ideas labels Mar 26, 2021
@eminence
Copy link
Contributor

Your summary indicates that Alan is writing a library (and so this clearly has links to #49 and #45 as you already mention). But this got me wondering.... if Alan was only writing a binary, would he feel the same levels of doubt? He might not, but I think it's still possible. I wonder if there are any personal accounts of someone so overwhelmed by all the decisions needed to pick a HTTP library that they hesitated using rust for their new binary project

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Mar 26, 2021

I can definitely imagine getting held up when writing a binary, but it'd be nice if we could cite an actual example.

@rylev
Copy link
Member Author

rylev commented Mar 29, 2021

I think this is also relevant in the binary case but perhaps less than in the library case. In the binary case, the choice impacts only the code you (and those working with you will write), there's no need for down stream considerations. In such a case picking a concrete HTTP implementation can be easier as you "just" need to make a choice that works for your project. In the library case you need to accommodate all possible uses of your library that you want to support.

@ririsoft
Copy link

Hello,

Do you intend to cover usage of HTTP libraries for building HTTP micro services within this issue, or you plan a dedicated issue for that too, or do not intend to cover web services at all ? I believe async is at least as much relevant server side as client side.

@cortopy
Copy link
Contributor

cortopy commented Mar 30, 2021

I don't know the background and scope of the personas in this story but, if I may, I'd like to extend Alan's story a little bit because the situation is even worse than in the first description. This story is a bit different in that Alan is not writing a library, but assessing the feasibility of Rust as a language ready for the web (this is a HTTP story after all!):

  1. Alan is a "GC'd language" developer. He wants to test how feasible it would be to migrate an old API server into Rust because he has heard that if a program compiles in Rust it will most likely work
  2. For this, he starts by picking one of the simplest endpoints. It is so simple that all the request handler does is pass arguments from the API request to a vendor's endpoint. That's it
  3. Alan learns that there are many choices for HTTP clients. Actually, this doesn't overwhelm him because he knows it's the same for Javascript (node's http, axios, browser's native fetch, isomorphic fetch, etc.). So he just picks Surf, simply because he understands the examples in the docs. No big deal
  4. Alan finishes his proof of concept and it's all so good. Writing a request in Rust is actually very easy!
  5. He then picks a HTTP server. He goes with actix-web, simply because it's popular and has heard of it
  6. Alan finishes a HTTP server with one endpoint, which uses Surf to make a request to another API
  7. The program compiles and starts ok
  8. And then, when hitting the endpoint, the program panics. Alan is deflated because it turns out that, like his favourite GC language, Rust can panic. In fact, he concludes that if a program compiles in Rust it can still crash for unknown reasons
  9. The error is very cryptic but somehow Alan learns that Surf only supports async-std and actix-web is written for tokio.
  10. He migrates from Surf to the latest reqwest
  11. Again, program compiles and starts
  12. But then, another cryptic error. This time the issue is that actix-web at the time of writing does not support tokio v1, while reqwest has already migrated.
  13. If Alan hasn't despaired yet, he learns that he has to find the latest reqwest version with the same tokio version as actix-web

Takeaways

  • HTTP library is a bit generic, does it include http client libraries, servers, both?
  • When Alan is able to finish his POC he learns that it's not just about picking the right library, but also digging into each and every one dependency of your project. If it happens that two dependencies require different runtimes things will go kaboom. This is unheard of in any of the languages he knows
  • Furthermore, even if you can tell out loud the main characteristics of major runtimes (tokio, async-std, smol, etc) you also have to know the history of each, as a dependency using tokio v1 is not compatible with a dependency using 0.3

@eminence
Copy link
Contributor

My initial read of @rylev's summary is mostly about choosing a http client library, and doesn't go into using that library (though this is an obvious next step).

A lot of Alan's pain that I see in your comment @cortopy is perhaps reflected in the Alan started trusting the Rust compiler, but then... async story. Do you think this story covers the experiences you outlined above?

@nikomatsakis
Copy link
Contributor

This sounds very similar to that story indeed, though it highlights some different causes for pain-- in particular it seems to be touching on version incompatibilities as well.

@rylev
Copy link
Member Author

rylev commented Mar 30, 2021

The story is about selecting an HTTP client implementation in an application where HTTP is a minor implementation detail and very much not central to the application itself. What is a simple choice in many languages is not simple in Rust. In fact, @cortopy seems to have benefited from coming from JavaScript where there is also an abundance of choice, but as noted, in Rust choice of HTTP client implementation can have actual consequences on whether things work or not. This is the central lesson from this story, choices that are trivial and often completely inconsequential in other languages, have an outsized impact on Rust async programs. For someone who tries to "find" the right answer, it will take a long time to come to the actual correct answer: choice of HTTP client library depends on other factors.

Indeed, I think @cortopy's comments seem better served by the trust story.

@cortopy
Copy link
Contributor

cortopy commented Mar 31, 2021

@eminence @rylev the trust story is indeed very similar to mine. There are a lot of commonalities between the two and even the examples are similar. I must confess I only discovered this repo yesterday and hadn't read it, so that's my bad. Sorry.

If I had read it, I wouldn't have put so much emphasis on the compiler part, which, as you say, is a big part of what I wrote.

But as @nikomatsakis mentions, there is more to it. I mainly write APIs and web applications, and so I live, breath (and sometimes die!) in a completely asynchronous world. If one looks at https://www.arewewebyet.org/, every single library mentioned there is async. And so if Alan was to write a http server his Cargo.toml will at some point end up with 10-20 dependencies, each with its own requirement for an async runtime.

This is out of scope for the initial story as suggested in this thread, but it also feels to me that just picking a http library is too simple of a task. As I mentioned, having tons of libraries for the same thing is bread and butter in other languages like Javascript. What feels particularly painful to me is the fact that choosing a HTTP client would rarely happen in isolation, and so Alan would also have to consider if he needs other async libraries. In an ideal world, he should also know which libraries he'll need in the future in order to make the right choice.

This last bit is what I think is not included in the trust story.

@nikomatsakis
Copy link
Contributor

@cortopy I think the story we were sketching today -- see #111.

I'd like to know if you think there is something not covered, because maybe you could write that story :)

Or extend an existing one

@eminence
Copy link
Contributor

Another option: We could also consider a "sub-story". We haven't really talked about what that might mean, but it could be something like a new .md file (either in the status_quo folder, or in a subfolder). It could contain a variation of the trust story (with a different focus, or additional details that were not part of the original story). Then we'd update the trust story with a new FAQ entry that says something like "Are there other variations of this story? Yes, see this sub-story"

@nikomatsakis
Copy link
Contributor

Sure, why not :)

@cortopy
Copy link
Contributor

cortopy commented Mar 31, 2021

@nikomatsakis I'm not too sure if that story gathers my experience with Rust. I've not published a library yet, but I have consumed all the most popular ones. It seems that Alan and Barbara are "producers" (sorry, probably not a good word to describe people) of libraries.

My urge to write in this thread comes from the point of view of the "consumer". It's very likely that the library Alan and Barbara are writing has a limited scope. That in itself is a luxury, especially if they aim for one thing and one thing only. "Consumers" of libraries, on the other hand, will have a very long list of dependencies to work with: http client, http server, pub/sub routines, websockets, ORMs and database connections, caching in remote stores, etc.

In that regards, it surprised me the conversation about whether to use async or not. In the story I have in mind it's an absolute given. No one in their right mind would write a synchronous web server like it's the nineties

@eminence I'd be more than happy to write a sub-story. Maybe sub-stories could be linked to more than one (trust and http client)?. I think my story would begin with something like:

1. Someone visits https://www.arewewebyet.org/
2. As a result, s/he thinks Rust is great to write a REST API because async support seems to be ready in all those libraries
3. And then similarity with story x
4. But also something different

@rgreinho
Copy link

As a beginner in Rust, I would like to add to this thread with our real-life experience. We are currently facing issues which make me relate to this story (and are preventing us to switch to Rust):

We are trying to rewrite some of our services from Python to Rust and are looking to achieve the following:

  1. Read a bunch of URLs (size varies, but about 1000 per batch)
  2. Do an HTTP GET request for each URL asynchronously
  3. Log the failures and process the results

What we did not succeed to do so far is:

  1. Send the requests by batch. If we send the 1000 requests at the same time,
    our server closes the connection and the process panics. Ideally we could
    buffer them to send at most 50 at a time. We could split the batches manually,
    but we hoped the HTTP client or the FuturesUnordered container would handle
    that for us.
  2. Handle errors. Failures should be logged and should not crash the
    process. We plan on using tracing-rs for the
    logging as it is part of the tokio stack.
  3. Implement Fibonacci or exponential retry mechanism on failure.

For reference, the stackoverflow question where I was looking for help.

@nikomatsakis
Copy link
Contributor

@cortopy

I don't totally understand it yet, but I'd love to see the story you're talking about! =) That said, i'm going to move your comment to a different issue, since it seems to be distinct from this particular issue. I'll leave follow-on comments there.

@nikomatsakis
Copy link
Contributor

@rgreinho I'm going to break this story out into its own issue too! I'd love to hear more about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers help wanted Extra attention is needed status-quo-story-ideas "Status quo" user story ideas
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants