Hacker News new | ask | show | jobs
by phtrivier 563 days ago
> State can be persisted (e.g., to storage, database or event log) between messages. If an actor crashes, it can recover its state on another node and resume processing.

And that's the part I never managed to solve, personally. The state of actors tend to look "a lot like" your domain objects, but you don't want to store it until the very end.

Do you have a data-model for each actor to store their own snapshots ? When do you snapshot ? When do you sync with the "ground truth" ? Do you have different tech for each kind of state (eg "term storage" for actors, then relational db for ground truth ?)

2 comments

> When do you snapshot ?

In Durable PHP (an actor system for PHP), it tries to achieve at-most-once processing guarantee (though more often than not, it is exactly-once).

1. commit the current state

2. send outgoing messages

3. ack the original event

If we fail before 1, we simply retry

If we fail between 1-3, we simply rewind and retry

Then, it assumes that your actors don't have any side effects. (Otherwise, "retrying" is not an option.)

I found that surprisingly hard in most applications - and I think that's is a limitation of the actor model _in practice_, that is often overlook because it's only an implementation detail that does not really exists _in theory_.

Durable PHP has a way to guarantee exactly-once side effects through "activities" (I assume you are talking about the outside world side-effects, not internally). Trying to do the same activity twice will simply result in merging with the previous execution. This isn't integrated with actors -- mostly because I hadn't thought about it before. It wouldn't be hard to do though.

However, in most async systems, you can only guarantee at-most-once or at-least-once; exactly-once is quite hard (and why there is a dedicated way to do it in this framework).

Internally, messaging is set up to guarantee at-least-once and duplicate messages are ignored (as well as dedicated ways to ensure deterministic execution).

This is what I’ve struggled with when trying to learn erlang/elixir/gleam:

If I go all in, then modelling as actors makes sense. The domain model is modelled as in-memory actors, using erlang features for persistence and what not.

But most of the time this isn’t what we want in modern software: instead our state is in a database and we are executing in a request-response setup. This seems to be mismatched with actors, as, it seems to me, at least, you’re mapping the database states into your actors on each request and then back on response, at which point, what do actors actually buy you?

The same mismatch exists with OO too, of course, but with actors there are a bunch of benefits that you get by going all in, which it seems to me are lost if you’re simply building a database backed request-response system.

I mean, many of the OP’s pros of actors rely on actors being long lived things, rather than short lived within a request.

Maybe I’m just missing something. But maybe it’s also just not suited to typical web api backend?

a few years back i had one side project that i did in elixir/phoenix felt like a good fit specifically because it had a lot of state that needed to live outside of the request/resp cycle but also didn't live in a db

Specifically the project was an app that ran terraform commands inside an actor and streamed the logs to the browser

each actor had a terraform config and each message was a command to run on that config

so in that case the actor model felt like it aligned really well with how the program needed to work