Actix Web 3.0
paper.dropbox.com
paper.dropbox.com
Is there any effort to bring a Rails/Django like framework to Rust? AWWY [1] seems to indicate that there isn't anything like it in the Rust ecosystem, but I'd be curious to know if there's anyone working on something in that direction. All of the frameworks I've seen seem pretty "bare-bones" by the standards of Django/Rails (then again - it's hard to beat these frameworks in terms of feature-completeness).
In my experience, frameworks like Django and Rails shine when you have to collaborate with large teams on solutions though - the fact that there's comprehensive documentation, best practices, and clear standards make it so much easier to work together on a project. I do think Rust brings a lot of assets through its type systems when collaborating, but rolling your own auth/admin dashboard/orm is a hefty investment for most mid-size companies.
Where I do find issue is that the lifecycle for their generic view API can be opaque. The docs have been improved there lately though.
I’ll echo other comments in that Django allows new developers with no experience in Django to be productive quickly. The docs are the MVP there and cover everything from tutorials to in-depth feature write-ups with examples and best-practices.
The only question is how much Rails-style magic we'd want. We could get pretty crazy with macros but IME the debugging story with the macros used in Juniper wasn't great (maybe it's gotten better?).
More like forcefully commandeered if memory serves.
$$("html")[0].classList.remove("paper-noir")Why do people insist on doing fixed menu bars? Does anyone like them? I don't think I have ever used a website where it improved the experience. Phones have had reactive scrolling for years, so a quick flick and you're at the top. So I don't even know what problem they're trying to solve.
They kept the name actif-web with actix in it because it was already quite established and they didn’t wanted to start from zero.
You can still use actix in your projet. It’s still actively maintained.
How it was resolved?
https://www.reddit.com/r/rust/comments/iqq8k9/announcing_act...
You cannot have it both ways, if you create an org on GitHub, a website, speak as a team "we"... seeing adoption will bring some expectations from your users and contributors, that are typically not just to beat other frameworks at TechEmpower benchmarks. I don't think many people want to use a performance experiment.
To be clear, I'm sure he also received a lot of unwarranted criticism, but that happens everywhere. It doesn't justify being hostile to legit contributions.
These mofos from Reddit who storm a GitLab ticket after it was posted there usually do not actually contribute to Open Source projects. They are pseudos who run their mouth but don't do the work. They are the ones who set up the wiki, but never write a single line of code.
Because from my perception it was more of the "unsafe Rust code is the devil community", which wasn't really using actix much beforehand. With that as a background you would be "punishing" the project for actions outside their core community (and control).
Performance wise, I don't think I need to repeat half the internet here, but I'll just say you'll be blown away by how little RAM a Rust app/container uses for the number of users hitting it. YMMV of course ;)
I thought that's only for syncronous libraries/frameworks? With async it blows out quite a bit. Everyone except rocket has got async functionality now too.
To illustrate this, consider the cost of spawning a new thread. The stack of a thread is usually a few MB, but lets use 1 MB for simplicity. Then 1000 concurrent connections is 1 GB of memory just for stack space.
With async/await, you don't pay a megabyte per connection because async uses perfectly sized stacks that are typically much much smaller than a megabyte.
Of course you can cap the number of connections, but IO speed puts an upper limit on how fast you can serve a connection, which means that the cap limits the number of connections you can serve per second.
Additionally, I doubt that the overhead at a few connections is large. There's a reason people call async/await a zero-cost abstraction, even if using a runtime such as Tokio introduces some amount of cost.
https://old.reddit.com/r/rust/comments/cych6a/async_performa...
The language is awesome and the performances too.
BUT, there is too many things that will distract you from being productive (compared to Node.js + TS or Go): unstable libraries, compile time is atrocious, cognitive load required to read Rust is high (break your flow), toolchain (RLS auto-completion) is weak, CI/CD costs are too high. You will spend most of your time solving Rust's problems instead of your project's problems.
In my opinion Rust is good on a 10-15 years timescale. But your project need to survive 10-15 years...
You can read the details here: https://gitlab.com/bloom42/wiki/-/wikis/engineering/language...
Based on your link, it looks like you are specifically referring to RLS. With the newer contender rust-analyzer[0] auto-completion is very good. In combination with TabNine[1] (for Rust the Pro version is free), auto-completion is pretty amazing by now.
I've added a little disclaimer because my experience was last year. The ecosystem is moving fast so some details may have changed (which is a cons for me, too unstable).
Totally unlike Node, right. ;)
With 5 years in PHP, 9 years in node, a few projects in Haskell and sporadic rust usage in the last couple of years: - PHP was great until they added autoloading and everyone started using a half assed package manager - node was great until everyone started using babel and they broke requires / import - python was ok until they split the ecosystem in 2 vs 3 - Haskell keeps getting better (stack, solved record name clashes) because things are rarely broken. It's too bad adoption is limited and there's not much commercial interest - Rust is my new favourite technology, it learned package management from node and functional programming from haskell. New features have been painless and easy upgrades
Rust offers perfomance improvements in CPU and memory usage of the core application logic, and it's almost never the bottleneck for the typical web apps. Almost always, they're limited by IO, and I don't see any reasons why it would be better on Rust that on Node. Also, Rust offers security of safe access to memory, but that's a problem that exists in C and C++, not in GC-based languages. Finally, Rust offers a great type system, but Typescript has a very good one as well, and offers a much easier transition for Javascript Node developers, as well as a much more machure NPM ecosystem.
Overall, I just don't see how Rust would make much of an improvement over existing state of affairs.
However the big caveat is the documentation and libraries are still quite lacking
And the mismatch between TS and JS is a pain, but that's why I'm looking forward to Deno.
Has anyone actually managed to find that this is the case? Just because your app is stalling on db queries doesn't mean it's "IO bound". Even the most trivial service that's just routing messages between two other services is likely to be radically faster when implemented in Rust vs JS.
OK, "IO bound" may not be the best description in this case. Because you're bound not by your ethernet card or operating system drivers, but literally by the work that's happening on a separate, database server's CPU. I should work on my terminology, thanks for the correction.
In my experience, it is usually waiting for DB. Regardless of whether your web app is well or badly written, it would get, at my estimate, would get no more than 5-10% request time improvement even if you made the app CPU infinitely fast, as 90-95% of the time is taken waiting for that database query.
But if you spend the same developer time rewriting all your ORM-generated n + 1 select statements to a single SQL query, you would still spend the same proportion of time waiting for the database, but your overall latency would get 10 times less. I've had some situations where I could get 10-20 time performance improvements by not touching application code at all, just tweaking the database indexes.
So, rewriting it all in a new language where you can, at most, 10% improvement, while you probably have areas where you can get 200-500% improvements seems unwise.
> Almost every web app.
No? My point is exactly that almost every web app is not io bound. They're just... slow. They write bad queries, they make bad usage of resources and block on requests, etc.
> Even WhatsApp scale runs on a “slow” dynamic language.
But that has nothing to do with being IO bound. Whatsapp, via Erlang, works by having tons of connections on a single box. And you can watch plenty of talks by them about how they've had to work with BEAM to get Erlang to actually be IO bound.
"IO bound" is a meme. Most people just mean "my queries are slow". Unless you're saturating your NIC, you're not io bound with regards to throughput, and unless your queries execute in ~<100ns you probably aren't IO bound on latency either.
However the important point is that they aren't CPU bound either. Most are "user acquisition bound" (like tens of requests per second peak). Some are more like "developer time bound" (cutting the server farm in half is not worth the cost in dev time).
Either way, using a slow development framework (including language, DB, etc.) that the developers like is a reasonable choice for what they're trying to do. (I personally wish most software was faster, but they have no reason to care what I think.)
Maybe the terminology around this could be developed some more.
4G latency 50ms
AWS inter AZ latency 1ms
Thread context switch 2us
The response times from things like search APIs even at FANG companies with vast resources and highly skilled engineers are often in the hundreds of milliseconds.
Rust can make app performance easier to reason about, improve performance, bring a real type system and all of this with a language which is just marginally harder to learn.
> oh wait, maybe someone is using this as any somewhere
There's a single option to disable any in all of your codebase. I've also found `unknown` type very useful for situations where you just don't care about what type you have, but would've had to use `any` before.
Rust has a pretty strict type system, and there's a lot of focus on correctness and reliability. Rust's enums with data are great for handling application state. This helps security, since the language stops you from doing entire classes of silly mistakes.
I've written some sites in Actix and it didn't feel too different from using express.js (with a caveat that I am experienced in Rust, so the language itself isn't an issue for to me).
"The Actix benchmarks which are winning are written at an extremely low level, with manual parsing, hardcoding header values as 'static string literals, ignoring HTTP methods, and basically being fast by skipping all of the work a real-world HTTP server would need to do to be effective"
The quote is 9 months old, but I doubt it changed since.
[0] https://www.reddit.com/r/rust/comments/e7xwma/rust_actix_is_...
[1] https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast...
v8, is a JavaScript engine. An oversimplified way to describe it, is that it has an interpreter and a JIT compiler. Compiled code is faster, but not all code is elegible for that. If you write code that can be optimized by v8, it can run very, very fast. Most of the time v8 will give you decent performance but if you want to maximize performance by minimizing deoptimizations (e.g.: tracing compiler behavior using --trace-opt --trace-deopt CLI arguments)... you will be consuming more time than using Rust.
libuv is a crossplatform library written in C that handles all the heavy lifting for node. Using libuv, node creates an event loop and a thread pool, where asynchronous operations can be scheduled and executed concurrently. It also takes care of file I/O and networking.
node gives you a decent level of performance when you can delegate most of the work to libuv, or built-in JavaScript functions. But when running user-defined code that is CPU bound, node is not the right tool for the job. CPU bound tasks tend to block the event loop, or make ticks long enough so that it becomes a problem.
Blocking or slowing down the event loop causes time sensitive tasks scheduled for future event loop ticks, such as processing events from sockets, to timeout. This can be prevented using worker threads, which are a recent addition to node... but almost all of node and its package ecosystem has been built around the absence of user-facing threads.
node can be used to build robust, highly available, performant and secure systems, but you need to know what you are doing and what the limits are. I think node is not the right tool for every job, but when it is, it can be highly productive and save time.
Security-wise, node is hard to audit. Packages tend to have many dependencies, and many packages are not built with security in mind. JavaScript itself is a languge that has been built with browser security in mind, but also, JavaScript is a language where almost everything is mutable, including built-in types. Prototype pollution is a big problem.
Rust is more flexible, doesn't impose you a threading model, you have access to many concurrency primitives, and all your code will be compiled in a much predictable way. I am not familiar with the security aspects of Rust. At least it seems much safer than C, where it is not hard to create unsafe code.
I don't think Rust can or will ever choose that, Loom works because Java already has a runtime. It'd be a much bigger step for Rust.
https://github.com/getsentry/sentry-rust/issues/187
I did build a nice rust boilerplate tho if any one is interested
NodeJS has build it concurrency model on callbacks which make non-trivial application difficult to debug and evolve.
Since then new paradigms have emerged such as promises and structured concurrency (https://vorpus.org/blog/notes-on-structured-concurrency-or-g...).
Rust has build it concurrency model with those new paradigms in mind, mixing them with it awesome ownership model. In the end Rust brings to the table much stronger guarantees on your code consistency compared to NodeJS, which can save you a lot of time and energy on complex concurrent system ;-)
JavaScript has had async/await for four years (and promises for even longer than that).
JS has its issues but it's not at all helpful when criticism is badly outdated either.
Also, I'm not sure, but I think Scala had Futures before bluebirdjs existed, which was the defacto Promise for JS, AFAIK.
Bluebird wasn't the first JS Promise library. It became the defacto library because it was faster than everything else.
Edit: https://en.wikipedia.org/wiki/Futures_and_promises has a history
I do know that promises existed a LONG time ago, I was just referencing languages that still are popular-ish. I thought the Scala implementation was pretty old, but it looks like Java actually has everyone beat.
Actix was already a great project but the community-driven switch mentioned here is a great step toward better support and broader adoption.
BTW is the fact the anouncement made on Dropbox paper has something to do with Dropbox as a company ? (I heard they are investing heavily into Rust)
Hu? I thought Rust was memory safe? At least that's how it's promoted.
What's the point of Rust when one of the flagship project (Actix) had memory leaks for years?
Also Actix has had a strained relationship with the Rust community for a number of years, because of Actix's cavalier attitude towards `unsafe`. The result of which is that the project is under new leadership, and safety is given a stronger emphasis. I also never really considered Actix a "flagship" project of Rust. It was popular and promoted itself, but it sort of set itself apart from the mainstream Rust community.
- Leaking memory doesn't cause Undefined Behavior. It might eventually cause your program (or your whole machine) to lock up or crash, but there are many types of bugs that can do that.
- Categorically preventing memory leaks is difficult without a garbage collector. The biggest problem is that you can use reference counted smart pointers like Arc<T> to create reference cycles. Preventing you from doing that at the language level would be too constraining for a lot of real world programs. (In practice, those programs need to break cycles manually using "weak" references.)
- The difference between "reachable" and "unreachable" leaks isn't so big in practice. For example, if I'm caching some data in a global HashMap, I might forget to clear that map, or I might not clear it frequently enough. If the map ends up consuming all of my memory, the effect on my program is the same as if I'd just leaked all that memory. Either way, I need to debug what's going on and make a code fix. (In fact, at least some of the leaks that the Actix post is referring to are this sort of reachable leak.)
For all these reasons put together, Rust allows safe code to leak memory. In fact, there's even a safe standard library function for doing it (https://doc.rust-lang.org/std/mem/fn.forget.html). But it's quite rare to run into unreachable memory leaks in practice, because destructors almost always free memory for you automatically.
It can be slightly less flexible, however in most cases if you are using this sort of flexibility your URL structure is too confusing anyways. Since you can group together an number of regular expressions and match them in O(n) with the length of the URL you clearly have a lot of flexibility available.
Of course I should probably check the real benchmarks because the NFA based approach almost certainly has more overhead.
However I feel bad knowing that every route I add is slowing down my app. And I have the impulse to sort my routes by popularity to improve performance. I wish I could just trust the framework to match "as fast as possible".
> if you are using this sort of flexibility your URL structure is too confusing anyways
A lot of the time, we don’t have a say in URL structure, unless we’re happy to break old URLs all the time.
Also, can we not use Big-O notation for quantities which never break 10,000, let alone 1,000. The cost of checking all the routes in order is going to be negligible.
I have a hobby project[0] running on Actix. A few days ago I updated from 2.* to 3.* and apart from one minor bug in a middleware (which seems to be fixed by now), everything worked without problems.
As for the ergonomics: I used Rocket about 2 years ago and it felt more ergonomic at the time but Actix has come a long way. I think it still hasn't reached the level of Rocket, but it's getting there.
That's the first time I've heard someone making a technical choice solely by something that is not technical.
Did you change from Actix because you're afraid that the controversy would eventually hit your own written software? Or just felt bad supporting something that others didn't want people to support? Would love to hear the reasoning behind the change.
I wasn't even upset about the unsafe. I didn't care.
Because performance-wise rocket is slower. But they're working on adding async support, after which they should be showing a lot better numbers.
There were two unstable features that Rocket was waiting on (which have been stabilized some releases back). Using nightly rustc is fine for the most part, but I wouldn't want to rely on it for production services.
In case anybody, like me, didn't know.
This post does not have to do with Dropbox engineering, which I do not believe uses Actix. But Dropbox does use Rust quite a lot - their storage layer and sync engine, among other things, are implemented in Rust.