
Actix: a small, pragmatic, and fast Rust web framework - fafhrd91
https://actix.rs/
======
the_mitsuhiko
We use it at Sentry for one of our services and the experience has been great.
The best part by far is that you can benefit from async io handling without
having to write every one of your views in an async fashion. All the async
complexity is offloaded into the extractors and the response sending.

~~~
ovao
Is this a new service built from scratch in Actix, or did you migrate the
service from something else?

~~~
the_mitsuhiko
New service entirely.

------
jason_oster
I evaluated a few different Rust web frameworks, where performance was the
deciding factor. A minimum viable echo server was put through its paces with
`h2load` on a relatively recent MacBook Pro. `actix-web` was literally 100x
faster than the next fastest competing framework.

The benchmark result really confused me. But you'll find that the `actix`
actors are extraordinarily lightweight and highly optimized around the equally
lightweight and highly optimized Futures. The design is hard to beat, from a
performance standpoint.

~~~
madsohm
Have you tried to create a more complex web page and have the web frameworks
render that as well? Sometimes being the fastest at the most trivial request
isn't enough, if it can't handle complex request fast as well.

Also, do you have a list of speeds for the frameworks you've tested?

~~~
steveklabnik
A lot of Rust frameworks use sync io. The first generation does because the
libraries for async didn't exist yet, and Rocket doesn't because (last I
heard), the author said that he didn't feel the ergonomics were there yet, and
that's one of Rocket's primary goals. So that leaves Actix, Gotham, and Shio,
basically. Gotham hasn't been tuned for performance at all. I haven't seen any
Shio benchmarks.

There are a lot though: [https://github.com/flosse/rust-web-framework-
comparison#serv...](https://github.com/flosse/rust-web-framework-
comparison#server-frameworks)

~~~
fafhrd91
From repo activity Shio seems dead. And here is for gotham
[https://gotham.rs/blog/2018/05/31/the-state-of-
gotham.html](https://gotham.rs/blog/2018/05/31/the-state-of-gotham.html)

~~~
steveklabnik
Yeah, that Gotham news happened after I made this comment. Good to know!

------
Dowwie
Actix-web is great! I've adopted it for my projects. I can take __full
__advantage of what Rust offers for concurrency and safety without going too
deep into the weeds. Documentation, a growing number of examples, a very
responsive author, and growing community are some of the reasons why I think
this project is going to play a major role in Rust 's web development story
going forward.

------
sudeepj
> fn greet(req: HttpRequest) -> impl Responder

Nice to see front page example using 'impl', the recent most improvement in
ergonomics. Before 1.26 things would be different. This makes me more
appreciative of the efforts from Rust team/community to improve the ease of
use.

~~~
rkangel
To explain this to people who don't know the background - this is about 'impl
NameOfTrait' in the return position.

It allows functions to return an object that provides a certain interface
without specifying the actual type of that object. This was only previously
true by wrapping it in a 'box', which meant a heap allocation and dynamic
dispatch. The 'impl trait' provides static dispatch and no other overhead, so
produces equivalent code to returning the type directly, but with all the
abstraction flexibility that you want.

~~~
ejanus
What is the use case ? Is there simple examples one could go through?

~~~
iopq
Usually you return a closure with impl Fn. Another use case is to return an
iterator.

I wrote a post about it. Let me know if it helps.

[https://medium.com/@iopguy/impl-trait-in-rust-explanation-
ef...](https://medium.com/@iopguy/impl-trait-in-rust-explanation-efde0d94946a)

~~~
ejanus
Your code is nothing but Magic . I have spent time trying to wrap my head
around it. I am almost there but I don't understand .map(<&str>::into) .
Monoid implements String

~~~
ejanus
Finally, that code is itched in my brain

------
nevi-me
I've had relatively good success moving some microservices from Kotlin to Rust
(mainly saving about 90% resident memory util). I picked up Actix recently,
and so far I'm enjoying using it. If Rust library support for geospatial tools
was as good as turf.js, I'd be able to move a lot more stuff into Rust.

~~~
urschrei
Turf development is funded by Mapbox. If you need more Geo functionality than
that provided by [https://github.com/georust/rust-
geo](https://github.com/georust/rust-geo) (I'm one of the developers),
contributions are actively encouraged, and we're happy to mentor people.
Alternatively, feel free to pay for some dev time if you need something
specific (e.g. OpenCage paid to have their geocoder included in
[https://github.com/georust/rust-geocoding](https://github.com/georust/rust-
geocoding), dual-licensed as Apache / MIT).

~~~
nevi-me
Hi urschrei, I naively tried to port turf to Rust, but from my past experience
[0] and flaky time commitment in the past; I thought it'd be too much to do
alone.

I've seen georust, and it's on my backlog. There's a few functions that I saw
missing (that I actively use). With mentorship, I'd love to contribute them.
I'll open some issues and introduce myself in the coming days.

[0] [https://github.com/nevi-me/turf-kotlin](https://github.com/nevi-me/turf-
kotlin)

------
znfi
Not sure if I'm missing something, but for the Techempower Bencharks [1] I had
the impression that the bottleneck for other rust libraries were in accessing
the database rather than handling http requests. However, looking at the code
[2] it seems that the Actix solution isn't doing anything special with regards
to this. Can someone give a quick description of "what" is causing such a huge
performance boost for Actix compared to other frameworks?

(I might add that this is a question I've had for a while, and I did not check
the source at [2] in detail today.)

[1]:
[https://www.techempower.com/benchmarks/](https://www.techempower.com/benchmarks/)

[2]:
[https://github.com/TechEmpower/FrameworkBenchmarks/tree/mast...](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix)

~~~
steveklabnik
These kinds of tests are heavily reliant on having async IO, and
[https://news.ycombinator.com/item?id=17194761](https://news.ycombinator.com/item?id=17194761)

~~~
znfi
Any chance you could elaborate on this, because I dont really understand how
it answers my original question.

I have not checked recently, but last I saw, the database libraries for rust
did not use async IO. Looking at (what I presume is) the code for the
benchmark [1], it seems it imports the postgres and diesel crates. Last I
heard diesel did not support async [2] and looking at the postgres crate [3]
it does not mention async, which I assume it would in case it was supported.

My whole point was that, sure, I can see how async IO is important for
handling many concurrent http requests, but each of those requests would still
have to pass through the synchronous database driver which uses threadpooling,
right? Or what am I missing here? I can see how it has great performance on
the plaintext and json benchamrks, but I dont understand what gives it such a
large boost in fortunes or multiple queries.

For example, Iron is doing 300k at plaintext/json benchmarks, but drops to 18k
on fortunes, and the way I remember the benchmark code it is written in a
fairly straight forward way. If the database layer supported 160k requests per
second I dont see why we would see such a huge drop? (Edit: 160k is the
performance of Actix on fortunes.)

I also recall seeing numbers on the 10k order of magnitude from doing naive
benchmarks with the various database libraries available, without any http
part to the application. But I'm not sure, maybe I'm missing something or
remember incorrectly?

[1]:
[https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast...](https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/frameworks/Rust/actix/src/main_pg.rs)

[2]: [https://github.com/diesel-
rs/diesel/issues/399](https://github.com/diesel-rs/diesel/issues/399)

[3]: [https://crates.io/crates/postgres](https://crates.io/crates/postgres)

~~~
steveklabnik
> I can see how it has great performance on the plaintext and json benchamrks

I actually forgot the DB tests were implemented; when I was sending in PRs, I
was mostly thinking about plaintext and JSON, not database stuff. Sorry about
that!

However.

[https://actix.rs/docs/databases/](https://actix.rs/docs/databases/)

> Technically, sync actors are worker style actors. Multiple sync actors can
> be run in parallel and process messages from same queue. Sync actors work in
> mpsc mode.

So, you're still getting _some_ degree of parallelism here. I wonder if that's
it?

(You're right about the fact that the DB APIs are currently synchronous.)

------
kibwen
It appears that Actix's primary author works for Microsoft, does anyone know
if Microsoft is using it internally for anything?

~~~
fafhrd91
we use actix. but that is all i can share :)

~~~
kibwen
Have you spoken with the Rust core team about Microsoft's use of actix? They
love getting feedback from commercial users, and I believe they are willing to
sign NDAs when necessary (there's certainly plenty of commercial users they
seem to be unable to tell me about, and I ask often :P ). I'm happy to put you
in touch with them if you'd like; see my email in my HN profile (and this
invitation goes for anyone else out there using Rust in production capacities,
of course!).

~~~
tuananh
He's the author of actix

~~~
cies
So MSFT uses Rust. :) That's actually quite a newsworthy thing, could be a lot
more newsworthy if we knew the purpose it was used for was some mission
critical component that also needs to be blazing fast.

Looking at Rust's strengths, and that MSFT has languages/compilers of it's
own, the use case is prolly "mission critical component that also needs to be
blazing fast". But for now we're guessing.

~~~
pjmlp
Oracle also uses it, and they changed the Java ONE conference to be Oracle
Code ONE conference, including Go and Rust related talks.

~~~
steveklabnik
This is very cool! I’d seen their open source work but not seen this.

~~~
cies
I've learned to hold my cheering whenever I read Oracle and open source in
close proximity.

~~~
steveklabnik
I hear you. At the same time, the particular project they're doing is an
implementation of an open standard, to provide an alternative and prevent
monoculture, so seems good to me. I'm not involved in the container space, so
I can't speak to the quality, but that's what it looks like from here.

------
jsandler18
I tried using actix for a recent project. I just could not get it to do what I
wanted to. It always felt like a fight. I switched to rocket and everything is
so much easier.

Everyone is saying great things about it, but I just want to point out that
it's not for everyone.

~~~
tormeh
Don't know anything about Actix, but can confirm that Rocket is excellent. The
actor abstraction is very interesting, though.

Anyone have any insight into how Actix and Rocket compare? I'm interested
mostly in ergonomics and safety.

~~~
jdright
I've done a simple hobby project in Rocket and ported to Actix.

I'm not experienced with web services and my project was very limited for
learning purposes, here my take away:

I like both and for me Rocket was way more ergonomic for creating routes
dealing as if they're simple functions where input and output are dealt
automatically with (from request and to response).

Actix advantage is actors and is easy to be fully async, I had some issues
dealing with it but most of my troubles were extracting request data and
building responses.

When actix-web will support magic as Rocket (once proc-macros becomes stable)
then actix-web will have the edge if Rocket don't become async-ready and
stable before.

For both it is only question of missing stable rust features and actix-web is
already running on stable.

actix-web: \- easy \- async \- stable

Rocket: \- stupidly easy \- sync \- nightly

------
chewbacha
I recently ported a very small micro service from Rocket to Actix and found
the migration to be painless. In fact, it's use of types and inferencing along
with integration with Serde made it very easy. It also worked on stable-rust
and can work with connection pooling against postgres. This makes it a winner
in my mind.

I'm excited to use it again in my next service.

~~~
dorfsmay
What motivated you to move away from Rocket (just curious, I've only used
Iron)?

~~~
chewbacha
Honestly, it was not being able to target stable that prompted the switch.
Then after using actix I was impressed.

------
fafhrd91
recent TechEmpower benchmarks results

Citrine:
[https://www.techempower.com/benchmarks/#section=test&runid=6...](https://www.techempower.com/benchmarks/#section=test&runid=60fab9eb-a5ad-49cb-
aefe-24ad0f377122&hw=ph&test=plaintext)

Azure:
[https://www.techempower.com/benchmarks/#section=test&runid=b...](https://www.techempower.com/benchmarks/#section=test&runid=b837bda0-fb68-4a98-9b25-eaad92039cea&hw=ph&test=fortune)

------
infynyxx2
Browsing thru Actix guide
([https://actix.rs/actix/guide/](https://actix.rs/actix/guide/)), I didn't
find any explanation regarding what will happen when actor(s) crashes or how
crashes[1] are being handled?

[http://wiki.c2.com/?LetItCrash](http://wiki.c2.com/?LetItCrash)

~~~
fafhrd91
first, you need to define what is crash in rust means. panic or error. in
general case you can not recover from panic. in case of error, type system
prevents unhanded errors in actors. you can restart actor, but that is
controlled by developer action.

~~~
e12e
A panic in an actor will take down the whole (rust) server?

~~~
fafhrd91
one thread in best case. But process may die. Depends on panic

------
SloopJon
I came across this the other day while looking into Flow, the C++ extension
used to write FoundationDB. This Github issue asks about a benchmark on which
Flow claims really good results:

[https://github.com/actix/actix/issues/52](https://github.com/actix/actix/issues/52)

Actix does pretty well too.

------
stusmall
What a great looking site. I've been really exciting about actix for a while
now. We just started some internal experiments with it here and I'm looking
forward to more.

~~~
topspin
Agreed. Good site.

This is an aside, and I sincerely apologize for that, but I am compelled...

I'm reading the greeting/hello-world example on this nice site and I notice
unwrap_or(). That is a poor name: can it panic, as suggested by the "unwrap"
part (I have just enough Rust to know that,) or can it not, as suggested by
the "or" part? The name is inherently ambiguous!

It's as if the .unwrap() that is festooned throughout such example Rust code
has become so ubiquitous that someone felt it had to be used and so tacked on
"_or". Why couldn't it just be .or() or perhaps .default()?

And so I investigate and things go rapidly downhill from there. Consider:

    
    
        unwrap
        unwrap_or
        unwrap_or_else
        unwrap_or_default
        or
        or_else
    

Good grief. The word ambiguous seems inadequate to describe what has emerged
here.

Again I'm sorry; this is clearly off topic, probably badly naive and possibly
inappropriate in a few other ways to which I'm pathetically oblivious. I
couldn't help myself.

~~~
masklinn
For prefixes, unwrap mean Option<T> -> T while or means Option<T> ->
Option<T>[0].

For suffixes, "else" means executable code (a closure).

> > It's as if the .unwrap() that is festooned throughout such example Rust
> code has become so ubiquitous that someone felt it had to be used and so
> tacked on "_or". Why couldn't it just be .or() or perhaps .default()?

Because Rust doesn't have function overloading and thus you'd be missing most
of the cases?

[0] or more generally Wrapper<T> -> T and Wrapper<T> -> Wrapper<T>

~~~
topspin
>> Because Rust doesn't have function overloading

That is the insight I needed. Thank you.

Rust seems novel in that despite having powerful abstractions and a rigorous
type system it does not support overloaded functions. I gather from some of
the discussions about it that this design decision greatly simplifies the
compiler implementation; supporting function overloading would necessitate
answering several very tough questions such as whether a function can be
overloaded on argument lifetime.

So the Rust standard library has established conventions (in this case
'unwrap', 'else' and or 'combined' in various ways) to deal with the
permutations that naturally emerge given the lack of function overloading.
It's important understand this and inculcate these conventions, particularly
when designing interfaces for use by others.

~~~
masklinn
> Rust seems novel in that despite having powerful abstractions and a rigorous
> type system it does not support overloaded functions.

Neither Haskell nor ML (incl. its children) have function overloading.

------
deft
Looks nice, really great landing page too. Informative and concise, didn't
leave me asking "what is this?"

~~~
_wc0m
Ought to be good, site was designed by the creator of Flask :)

~~~
deft
Wow, that's cool. Maybe I should finally learn rust!

------
berkus
I started porting one of rocket-based synchronous services to actix-web and so
far I'm pleased with the process.

------
reacharavindh
I have just started playing with Actix-web. Rust-Noob as well. The yellow
world example compiled to a binary that was ~ 5 MB.

As a general case, Actix-web pulls in a lot of dependencies at install, and
compile time.Are all of those dependencies really necessary for a hello world
scenario?

Being a Rust newbie, I thought maybe I was using the wrong tool and started to
look at hyper instead..

~~~
sondr3
5MB is nothing compared to what you'd use for a similar project in node or
Python or Ruby. Sure, it's not the tiniest it could be, but using tools like
strip, not including debug symbols etc it gets pretty damn small. Honestly
though, at that point I think size becomes entirely pointless to even mention
unless you need to run it in a super constrained environment, which you're
probably not when you're using the standard library :)

~~~
timlyo
There's a lot that can be done to shrink a Rust binary[0]. A copy of the
summary:

\- Compile with --release.

\- Before distribution, enable LTO and strip the binary.

\- If your program is not memory-intensive, use the system allocator (assuming
nightly).

\- You may be able to use the optimization level s/z in the future as well.

\- I didn’t mention this because it doesn’t improve such a small program, but
you can also try UPX and other executable compressors if you are working with
a much larger application.

[0][https://lifthrasiir.github.io/rustlog/why-is-a-rust-
executab...](https://lifthrasiir.github.io/rustlog/why-is-a-rust-executable-
large.html)

~~~
steveklabnik
s/z was made stable ten days ago: [https://github.com/rust-
lang/rust/pull/50265](https://github.com/rust-lang/rust/pull/50265)

So, two releases :)

------
zarvox
I've recently been building an IRC bouncer and webapp with Actix, and it's
been really smooth sailing so far -- excellent documentation, extensive
examples, and everything I've touched so far has just worked the way you'd
expect it to. It's a gem of a project.

~~~
MrBuddyCasino
Wanted to do the same exact thing! Is it public?

~~~
zarvox
Not yet (still incomplete) but I'd be happy to drop you a line if/when that
changes - send me an email?

------
LambdaComplex
Can someone explain to me what advantage the actor model provides for a web
server?

~~~
Diggsey
Actors are generally a very powerful abstraction.

To give a specific example: they can be used to mediate access to a resource
without requiring complex synchronisation: instead of sharing a piece of
mutable state (like a cache) and protecting it with a lock, you can ensure a
single actor accesses the cache, and other code communicates with that actor.

This is particularly useful with asynchronous code, because it's not possible
to have a fair, asynchronous "passive" mutex without suffering from the
thundering-herd problem. If you try to implement such a mutex, you will find
yourself needing to queue up lock requests and responses, and you will end up
reinventing the concept of an actor.

------
kev009
This looks really nice! I learned Scala primarily to use the Play Framework
which is a fabulous way to build large web applications. This looks
spiritually quite similar, but with the advantages of Rust.

~~~
user1241320
I started using Scala for Play and Akka and I'm currently using Akka[1] in
production in many projects.

[1]: [http://akka.io/](http://akka.io/) Akka is the implementation of the
Actor Model on the JVM.

------
ccccccccccccc
Question: What is the point of making the fastest web server possible when any
kind of datastore attached to the server is going to be the bottleneck?

~~~
tene
That's a good question, and something that's not always obvious without having
been in a situation to get advantage from such an improvement.

First, even if waiting for a response from the database is the largest single
contributor to your response time, and if you're running an extremely low-
traffic service, there's still benefit in reducing your total latency

Second, if you're not running a low-traffic service, and have enough requests
that you're approaching the memory or cpu capacity of your web server (or have
an existing application that's already deployed across multiple servers),
making significant reduction in your CPU or memory use can let you handle
quite a bit more traffic with less hardware.

Third, not all web services involve little more than making a request to a
single external slow database. The data for your service could be: * Static *
Ephemeral, kept in-process * In a database on the same server * In a fast
database (memcache) * Require nontrivial processing * Processed by a separate
service you're just acting as a proxy for

------
rubyfan
Why do so many Rust projects lead with telling you their number one feature is
type safety? It’s Rust we get it, stop telling us about your type safety!

Also, what problem is this solving that countless other near identical web
frameworks don’t already solve?

~~~
smt88
Even with an opinionated type system, it's possible to slack off a bit. There
are different degrees of strictness/specificity when composing types.

------
some_account
I really love seeing rust making progress. It's a fantastic (with slightly
ugly syntax) language that I want to learn. :)

------
baituhuangyu
really？

------
baituhuangyu
really?

