
Actix – Actor Framework for Rust - Bella-Xiang
https://github.com/actix/actix
======
dmm
The naming is a little confusing here. This is Actix the actor model library,
not "Actix web" the web framework that's usually discussed.

Originally "Actix web" depended on Actix the actor library, but no longer.
Though they can be used together. And I think websockets still require actors?

I'm using both Actix and Actix web for a personal project. I like it a lot and
think the actor model is good fit for applications that don't fit well into a
request lifecycle.

My main pain point with it is the use of futures. Right now it's a huge pain
to have more than one return value in an Actor Handler, the functions that
handle actor messages. Even if you box the returned Future, you end up having
to use futures::Either a bunch and when you mess it up you get tons of
confusing errors filled with the huge inferred types.

Implementing something like:

    
    
      if (condition1) {
        return <future for service call1>;
      } else if (condition2) {
        return <future for service call2>;
      } else {
        return <no-op future>;
      }
    

Is a big pain requiring two layers of future::Either. Or I just don't know
what I'm doing, which is very possible.

async/await would be a huge improvement, but can't be used at the moment, even
though the current version of Actix uses std::future's.

~~~
kevinmgranger
> Even if you box the returned Future, you end up having to use
> futures::Either a bunch

That's really strange. A Boxed future is the end-all-be-all of not caring
about the underlying type. Would you mind sharing a snippet of code that shows
where you need both a Boxed future and Either?

~~~
dmm
You're probably right, I must be missing something. I'm also still on futures
0.1 because I'm still porting it to std::futures.

Here's an example of what I was discussing:

[https://github.com/dmm/exopticon/blob/c40d14c80c150ef6270732...](https://github.com/dmm/exopticon/blob/c40d14c80c150ef62707320085b8f9243160c8a8/exopticon/src/camera_routes.rs#L245)

The idea is that I want to implement a relative ptz move on a camera but some
cameras have a broken relative move implementation so in that case we instead
use a continuous move + a delay + a continuous stop. The final case is when a
camera has no ptz it returns Http::NotFound.

~~~
Arnavion
If you have

    
    
        if cond {
            Box::new(future_a)
        }
        else {
            Box::new(future_b)
        }
    

then by default, the type of the first Box will be concrete Box<FutureA>
rather than Box<dyn Future>, which is why you'll get a type error that
Box<FutureB> != Box<FutureA>

You'll need to coerce the first expression to Box<dyn Future>. The compiler
will auto-coerce the other one.

    
    
        if cond { Box::new(future_a) as Box<dyn Future<...>> } else { Box::new(future_b) }
    

See [https://play.rust-
lang.org/?version=stable&mode=debug&editio...](https://play.rust-
lang.org/?version=stable&mode=debug&edition=2018&gist=cd2d3fe1b68d430f1de3f0d4ad8ec3ac)

(This auto-coercion also applies to other situations where the type of an
expression must match the previous one's, such as with a slice literal where
the first element dictates the types of the rest.)

You don't need to coerce if the compiler can infer that the whole if-expr must
be of Box<dyn Future> type. This happens when the if-expr is being returned
directly and thus must have the same type as the function's return type, or
it's being assigned to the binding and the binding has been previously
inferred to have (or explicitly has) Box<dyn Future> type. You can test this
in the playground by returning the if-expr directly instead of binding it to
`result`.

~~~
estebank
A more stylistic pattern for this is to give the binding a type so that the
coercion of the if/else expression works automatically instead of using `as`.

Also, there's work being done so that this won't be needed by deferring
evaluation of expressions until the whole body has already been evaluated so
that inference with the naïve code will work at some unspecified time in the
future.

------
shawnz
What is the difference between the actor model and object oriented
programming? It seems to me like they are basically the same paradigm but with
all the names changed, and some additional restrictions like all messages
being async and objects only being able to process one message at a time. Why
is it necessary to create a whole new paradigm just to enforce such a style?

~~~
edejong
Your question is interesting from the perspective that the actor model could
be seen as the precursor to modern object oriented programming. Both the actor
model as defined by Carl Hewitt and the early object computational models as
they are defined by Alan Kay (Smalltalk) originated during the same period and
are based on similar philosophies of computation.

However, on the object oriented model track, due to practical reasons, its
definition descended into a single-thread dispatch system with full message
delivery guarantees. Locality was dropped (due to singletons) and the
distributed model was not maintained. Method dispatch systems were later
added, but could be considered a kludge. This also explains the mismatch
between remote systems calls (SOAP, REST, etc.) and the internal language.
Ideally, these would be the same.

With our modern systems design constraints, especially given distributed
systems, we need to revisit those early decisions. The Actor model is a good
blueprint for our designs. It is fundamentally decentralized, locality is
enforced and at-most-once message delivery is assumed. These allow us to
design and implement distributed algorithms which would be hard to implement
using traditional OOP methods.

~~~
sakian
Aren't they connected by the idea of active objects?
[https://en.wikipedia.org/wiki/Active_object](https://en.wikipedia.org/wiki/Active_object)

~~~
RossBencina
Based on the description in your Wikipedia link there is a relationship for
sure -- but I don't see a strong connection. Here's how I see it:

An Active Object is essentially an OO encapsulation of a worker thread. It
provides clients with a synchronous call interface where all results are
resolved asynchronously (e.g. using futures for results). Internally, the
Active Object converts client requests into asynchronous operations, enqueues
the operations, and executes them on a private worker thread using object-
specific dispatcher logic.

In an OO system, not all objects are required to be Active Objects. So there
may be a mixture of synchronous and asynchronous execution.

In contrast, in an Actor system all communication is via asynchronous messages
and there is no inherent requirement for multiple concurrent threads of
execution.

Active Objects use a mechanism such as futures to return results. On the other
hand, if there is a request-reply message exchange in an Actor system, both
the request and the reply will be separate messages. The client would receive
the result of a computation by receiving a message.

The relationship I see between Actors and Active Objects is that both require
some kind of queue for dispatching operations (since Actor behaviors are never
re-entrant). Active Objects convert synchronous calls into asynchronous
operation requests, whereas Actors use asynchronous messages for _all_ inter-
entity communication.

I agree with the GP that event loop programming is the closer OO analogue of
Actors.

------
habitue
Highly recommend Bastion if you're looking for a Rust Actor library / runtime.
It uses async/await etc, and has supervision trees and restart strategies
taken straight from Erlang/OTP

[https://docs.rs/bastion/0.3.4/bastion/](https://docs.rs/bastion/0.3.4/bastion/)

[https://github.com/bastion-rs/bastion](https://github.com/bastion-rs/bastion)

~~~
captain_crabs
would you even suggest this over riker?

~~~
habitue
I haven't used Riker, is it good?

------
dantodor
I'm amazed on how much discussion digressed to actix-web. Understandable, seen
the latest happenings there, but still... I tried quite a while ago Actix,
coming from Erlang/Elixir and Scala/Akka. While the cognitive load of using it
was not high, when I started my first test, I noticed one core being maxed
out, and all others sleeping, which was kinda unusual for me. I asked why, and
the author answered that it uses an event loop, so if you want it otherwise,
go away and use something else, like Riker... So I went away :) ... I would
assume this kind of behaviour has been corrected meanwhile (I mean the
library, not the comms), because otherway, it's just a Node written in Rust.
My 2c :)

------
andrewzah
Actix (the actor framework) is separate from what people are discussing here:
actix-web, which _supports_ actix). In earlier versions of actix-web it was
based around actix; I remember implementing actors and handlers. Since 1.0 or
so that got changed to more of a standard setup.

I’ll add my 2c on actix-web: in my opinion it tries to do too much. hyper
(simply based on tokio) is all you need for a fast async server. Anecdotally,
I know many people who basically use just this stack, over actix-
web/warp/tower etc.

There are other actor systems, like kay [0].

[0]:
[https://citybound.github.io/citybound/kay/index.html](https://citybound.github.io/citybound/kay/index.html)

------
xedrac
I'm currently in the process of removing actix from one of my projects and
replacing it with asyc/await and some channels. Actix comes with a ton of
dependencies and doesn't buy you a whole lot anymore.

~~~
Huycfhct
Yes. I would imagine Actix being out of favour now. Funny to see it being a
rust project shared on hn

~~~
slydo
What is in favor now?

------
ncmncm
Can somebody please summarize the outcome of the recent kerfuffle? I don't
mind which way it came out, but it seems worth knowing what it was.

I absolutely don't want any even-slightly-inflammatory answer.

~~~
_-___________-_
This is from memory, I would welcome any corrections.

Actix was written with a lot of _unsafe code_ [0], which some people
considered unnecessary and potentially dangerous in a web framework. In some
cases the unsafe code may have been performing better than equivalent safe
code. In other cases, it was possible to rewrite with safe code without losing
performance.

People submitted patches to replace unsafe code with safe code. The maintainer
of Actix responded with hostility to some of these patches, and (at least for
some of the patches) did not seem to see the reason why people wanted these
changes.

Subsequently, a lot of hostility was directed at the maintainer on various
public Internet fora.

Ultimately, the maintainer of Actix deleted the repository from GitHub, but
then had a change of heart and restored it, with a new maintainer.

[0] _unsafe code_ according to the Rust definition of unsafe:
[https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html](https://doc.rust-
lang.org/book/ch19-01-unsafe-rust.html)

~~~
burntsushi
A small but crucially important clarification: it wasn't just that there was a
lot of `unsafe` code, but that some portion of it was _unsound_.

You can read more about what I mean by _unsound_ in this context here:
[https://docs.rs/dtolnay/0.0.7/dtolnay/macro._03__soundness_b...](https://docs.rs/dtolnay/0.0.7/dtolnay/macro._03__soundness_bugs.html)

~~~
undecisive
Interesting - thanks for sharing that. Though that article does make things a
little clearer, I get the impression we should really have three circles on a
venn diagram - essentially, I'm decoupling the concepts of "unsound" and
"bug":

\- Bug - i.e. some unintended action of a piece of code

\- unsound - i.e. code that can be used (or abused) to produce unsafe effects

\- unsafe-bleed - i.e. code that cannot be proven to be safe at compile time,
or even potentially code that can be proven to be unsound, that a third-party
developer could legitimately use without knowing it was unsafe/unsound.

The question I'm curious about is what the proposed PRs fixed. It's clear they
didn't fix a bug; the API used was part of the undocumented internals (afaik),
and all internal uses of the code were reportedly clean.

It maybe "fixed" an unsoundness, future developers of the project may indeed
have misused this code and received undefined behaviour as a result (again, I
don't know how common or uncommon the particular misuse would be in the rust
community)

I don't know whether this fixed an unsafe-bleed though; whether a third party
has access to these objects and has the ability to combine them in such a way
as to produced undefined behaviour.

My question to you is: is this a Bug, such that the code did not perform as
expected; Is there a bleed of unsafety here, where the permissions model of
rust allows access outside the crate to these implementation details; or is it
just unsoundness - and if so, could the unsoundness have been mitigated some
other (more performant) way?

~~~
burntsushi
I don't have the time or desire to answer that question. That would require a
level of scrutiny into specific PRs and details that I don't think is
productive to go into. I think my clarification stands on its own. Gratuitous
use of `unsafe` is bad on its own, and unsound `unsafe` use is also bad on its
own. They are two different categories of problems. Both were present in
actix. These weren't the only issues, but others have addressed those. My only
point was to clarify that the issue wasn't just frequency. Soundness was also
an issue.

Whether this only impacts actix developers or whether it impacts users of
actix is, I grant, an important question in order to asses just how much you
should freak out about any particular soundness problem. (As dtolnay points
out, sometimes you don't need to freak out at all. So my statement includes
"zero amount." But I am intentionally conveying a bias here: some level of
freak out is probably appropriate in a high profile ecosystem level project
for Rust specifically. IMO.)

------
3fe9a03ccd14ca5
I’m really excited about this project. Using Akka was one of those things that
made distributed/parallel execution just “click”. Particularly useful was
being able to draw your architecture the same way one might draw an
organization on a whiteboard. Everyone can quickly understand what happens and
who is responsible for what.

------
polskibus
Out of curiosity - actix seems to be very performant compared to actor
frameworks implemented in other languages - would it be a good fit to
implement a database using it? For example mapping worker pool and workers to
actors?

~~~
rofrol
I would rather use linux io_uring
[https://www.reddit.com/r/rust/comments/f06y7m/comment/fguw9a...](https://www.reddit.com/r/rust/comments/f06y7m/comment/fguw9a3)

------
smallstepforman
Actors in principle (isolated objects assigned to threads) sound great until
you need to SHARE data, then you enter a new universe of compromises where you
need locking mechanisms (for performance), but no language semantics support
it natively. Pony introduced reference capabilities but that still created a
cludge for those times you needed synchronous access. There is no model yet
where locking primitives are associated with resource handles.

~~~
shanxS
> ... sound great until you need to SHARE data ...

If by "share" you mean one writer and others with read-only access, then
staleness of data is a question. In java we have volatile for that, I think
there is a similar keyword in C++. However, you'll have to maintain the
invariant of "one writer and others with read-only access". If you don't need
absolute latest version, you can do message passing/pubsub etc.

If by "share" you mean multiple writers, I'll have to question your design
decision. Why do multiple threads have to write to same memory location? Most
of the time, you can get away with partitioning/sharding.

If you disagree, I'd like to know why?

~~~
smallstepforman
Unfortunately, our objects are not isolated, they interact with the world, and
often need to be shared when we cannot copy the resource (performance). Eg. a
(partitioned) rendering surface may be written simultaneously, a physics
engine needs to know what objects are in the game world, multiple bank
accounts need to be updated simultaneously, etc. By design is not always
possible to sequence, some transactions must be atomic across multiple
objects.

~~~
ahasani
Yes they are, atom is in isolation, cell has membrane, we have a body we have
isolation and encapsulation in physics/chemistry/biology. In actor model
message passing is interaction. Since you mentioned game, check out
[https://github.com/aeplay/kay](https://github.com/aeplay/kay), which is the
isolation "objects" for
[https://github.com/citybound/citybound](https://github.com/citybound/citybound)
"physics engine". On multiple bank accounts, well an account is an actor, so
there is no problem there, please have a look at
[http://proto.actor/blog/2017/06/24/money-transfer-
saga.html](http://proto.actor/blog/2017/06/24/money-transfer-saga.html)

------
walkingolof
How does it stack up against more mature actor frameworks like Akka? (akka.io)

------
jamil7
Whats the state of Rust if I wanted to get into it for backend development?
I've looked briefly into Rocket and liked it but didn't delve too deep, I
understand Actix is one of the most mature?

~~~
_-___________-_
I wouldn't call Actix the most mature, but it's definitely the one that gets
talked about the most.

I built a fairly complex backend directly on top of Hyper[0] (it doesn't even
involve that much glue, really) in 2016 and have updated it as Rust and Hyper
have matured. It's actually a delight to work on, and I brought a new hire on
board recently who had no trouble getting up to speed, since everything is
just straightforward, idiomatic Rust.

I've looked at basically every Rust "web framework" that's been released since
2016, and I can't see any of them simplifying the codebase enough to justify
using them. Quite a few of these frameworks result in code that isn't obvious
to a Rust programmer who hasn't used that framework before, too, which I
consider a disadvantage (I prefer obvious over clever).

[0] edited to add for those that may not be aware: Hyper is a client & server
HTTP library. Many/most of the frameworks are built on top of it.

~~~
mamcx
> I wouldn't call Actix the most mature

Surely? I try several other for replace my .NET core project, and Actix is the
only one that barely get there.

Which other handle without much fuzz:

\- Auth (big!) \- Routing with state and db pooling \- Forms \- Templates \-
Encode/Decode all stuff (query string, headers, etc) \- Allow to inject
middle-wares \- Have (at least) the bare minimum of functionality like gzip
encoding \- And many other small details I forget now

I have worked, alot, with django, then use .net core and now Actix, and the
others rust frameworks are lacking badly as far I see.

What I see the rust ecosystem is lacking now is mostly around templating (need
more love for dynamic options!) and some stabilization around rdbms usage..

~~~
_-___________-_
Actix has a lot of features, but to me that's not the same as maturity. I
don't want one "batteries-included" framework, I want components (preferably
mature and relatively boring) with well-defined interfaces that I can use
together to build my backend.

~~~
mamcx
Thats is fine, but is surprising how many stuff you need to make a semi-
complex site. Is better for a ecosystem to have the "batteries-included"
framework that cover the needs of many and then specialize.

Django, ROR pull a lot of people into.

------
dragonsh
This framework's core developer has left, probably new community took it over.
Hopefully it will continue to be supported and developed.

Rust still has a way to go for being a mature eco-system for doing any serious
web programming work. Given the focus of Rust on systems programming, I will
still be careful to consider it for anything web related.

Hopefully situations like abandoning a project suddenly will not happen again.
[1] [2]

[1] [https://words.steveklabnik.com/a-sad-day-for-
rust](https://words.steveklabnik.com/a-sad-day-for-rust)

[2] [https://github.com/actix/actix-
web/issues/1289](https://github.com/actix/actix-web/issues/1289)

~~~
Dowwie
You seem to have a superficial level understanding about the Rust ecosystem
for web development and for the actix ecosystem. Yet, this hasn't stopped
others from trusting your opinion or agreeing with your comment,
unfortunately.

This post is for the original actor architecture. The next architecture, which
should have never been called actix, was based on a completely different
architecture. This second version prevailed and remains in use today, as
actix-net. Actix-web v2 uses actix-net. It features async-await syntax, is
feature complete, and the architecture is mature. The project includes a
guide, api docs, a vast collection of examples, and growing ecosystem. Actix-
net is very high-performance.

The main concern about any actix project was related to poorly communicating
uses of unsafe code, refusing to codify a policy about unsafe, and working
with others, respectfully, to address real undefined behaviors.

The author has retired from the projects, for now. Others have stepped up to
maintain and improve. It's very exciting to see people addressing unsafe
blocks. Most importantly, actix-web lives on!

The expectations and treatment of authors who spend hundreds of hours on
bleeding edge, open source work is also a major problem. This problem isn't
specific to Rust, either.

~~~
cdbattags
Hi @Dowwie, I'm one of those "others" you mentioned that's trying to fill
Nikolay's very large shoes!

Yuki (John Titor on GitHub), Rob and I are well on our way removing concerning
`unsafe`s wherever we can. Sadly, there are some breaking changes but that's
not stopping us and we're now headed to a 3.x release. No timeline on that
just yet.

The community has bounced back quite a bit ever since the transition and I'm
hopeful that actix-web will continue to be the leader-ish of Rust web
development!

Just the other day we even had the first example mix some async_std into the
mix (obviously, yes, some runtime weirdness with this)!
[https://github.com/actix/examples/tree/master/multipart-
asyn...](https://github.com/actix/examples/tree/master/multipart-async-std)

Happy to answer any questions y'all might have!

