Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Feb 23 09:16

    Neverlord on master

    Replace Coverity badge with LGT… (compare)

  • Feb 23 08:48

    Neverlord on master

    Fix LGTM warnings Merge pull request #1223 Fix L… (compare)

  • Feb 23 08:48

    Neverlord on neverlord

    (compare)

  • Feb 23 08:48
    Neverlord closed #1223
  • Feb 23 08:47
    lgtm-com[bot] commented #1223
  • Feb 23 08:02
  • Feb 23 07:35
    Neverlord milestoned #1223
  • Feb 23 07:29
    Neverlord assigned #1223
  • Feb 23 07:29
    Neverlord labeled #1223
  • Feb 23 07:29
    Neverlord opened #1223
  • Feb 23 07:25

    Neverlord on neverlord

    Fix LGTM warnings (compare)

  • Feb 22 20:21

    Neverlord on neverlord

    Support variant types in json_r… (compare)

  • Feb 22 19:35
    Neverlord labeled #1221
  • Feb 22 16:40

    Neverlord on neverlord

    Support variant fields in the j… (compare)

  • Feb 22 16:10

    Neverlord on neverlord

    Omit @type fields for nested ob… (compare)

  • Feb 22 07:11

    Neverlord on neverlord

    (compare)

  • Feb 22 07:10

    Neverlord on master

    Add new example for variant-lik… (compare)

  • Feb 22 06:53

    Neverlord on neverlord

    Add missing include (compare)

  • Feb 22 01:34
  • Feb 21 21:21

    Neverlord on neverlord

    Remove 'using namespace caf' (compare)

evolvingfridge
@evolvingfridge_twitter
how mobile "actors" (android, ios) can interact with CAF based cloud service ?
Dominik Charousset
@Neverlord
Depends a lot on your app. Is the App in C++ and needs an active connection while the user is interacting with it? Connecting to the backend directly via the OpenSSL module might be an option. Do you need an active session but want to stick to standardized interfaces? JSON over WebSocket might be an option. Etc.
evolvingfridge
@evolvingfridge_twitter
sorry, a bit new to this, can I build CAF actor for IOS/Android ? (seems like pthreads dependency might be an issue)
networking wise I have two abstract channels; first one is for synchronizing states between actors (on_client_connect etc.) the second one is for commands for modifying states.
I am not sure, to what degree CAF messaging will be sufficient for this or I will need to invest ~year of life to make it work. I am intending to implement own UDP protocol similar to Starcraft networking (have some experience from finance).
Dominik Charousset
@Neverlord
AFAIK, both iOS and Android have native SDKs. But I'm not sure what you'd get/expect from CAF on mobile if you're rolling your own UDP protocol anyway.
evolvingfridge
@evolvingfridge_twitter

I am still reading documentation what interests me is the core library as shared library for multiple OS/hardware.
As far my primitive understanding goes I/O would require work to utilize multiple UDP channels with re-transmigration logic. (I might be miss understanding abstraction)

From documentation:
"Messages that are sent via datagrams are limited to a maximum of 65.535 bytes which is used as a receive buffer size by CAF."
I think 65.535 should 65,535.

Dominik Charousset
@Neverlord
The UDP-abstraction mostly gives you a way to operate message-oriented on a socket, but there's no re-transmit or other higher-level functionality added. Yeah, should be 65k. :)
Yifei Yang
@Raining-yyf

Hi, is there a way to "remote_spawn" a class-based event-based actor? The example code shows "remote_spawn" a function-based actor. When I tried to remote_spawn a class-based actor, I got an error that "no matching constructor for initialization" of the actor class.

To (local) spawn the class-based actor, I just need to simply provide a constructor taking "actor_config &" as first argument, but for "remote_spawn", the error message shows the first argument should be "actor_control_block *" instead of "actor_config &", but there is no constructor for event-based actor using "actor_control_block *". Can anyone help me? Thanks!

Dominik Charousset
@Neverlord
@Raining-yyf can you share code/compiler error? Remote spawning generally goes through the middleman by name and passes constructor arguments as message: https://github.com/actor-framework/actor-framework/blob/master/examples/remoting/remote_spawn.cpp#L136
To register a class-based actor, you'd call add_actor_type<MyClass, A, B, C>("MyClass"), where A, B and C are the arguments required to instantiate this actor remotely.
Yifei Yang
@Raining-yyf

Sure, the following is actor_system_config I used in client and server side:

struct config : actor_system_config {
    config(int port, std::string host, bool serverMode) :
    port_(port), host_(host), serverMode_(serverMode){
      load<io::middleman>();
      add_actor_type<OperatorActor>("operator");
      opt_group{custom_options_, "global"}
              .add(port, "port,p", "set port")
              .add(host, "host,H", "set node (ignored in server mode)")
              .add(serverMode_, "server-mode,s", "enable server mode");
    }
    uint16_t port_;
    std::string host_;
    bool serverMode_;
  };

where OperatorActor is the class I wish to remote_spawn, derived from event_based_actor.

The following is the function I use to remote_spawn:

caf::actor graph::OperatorGraph::remoteSpawn(const std::shared_ptr<Operator>& op) {
  auto remoteSpawnTout = std::chrono::seconds(10);
  auto expectedActorHandle = operatorManager_.lock()->getActorSystem()->middleman()
          .remote_spawn<normal::core::OperatorActor>(node_.value(), "operator", make_message(), remoteSpawnTout);
  if (!expectedActorHandle) {
    throw std::runtime_error(fmt::format("Failed to remote-spawn operator actor '{}': {}", op->name(), to_string(expectedActorHandle.error())));
  }
  return caf::actor_cast<caf::actor>(expectedActorHandle.value());
}

where operatorManager_.lock()->getActorSystem() gives the actor_system of client side, node_value() gives the remote node already connected.

The following is the compilation error I got:

.../caf/actor_cast.hpp:154:12: error: no matching constructor for initialization of 'normal::core::OperatorActor'
    return {x.release(), false};
           ^~~~~~~~~~~~~~~~~~~~
.../caf/actor_cast.hpp:177:10: note: in instantiation of member function 'caf::actor_cast_access<normal::core::OperatorActor, caf::intrusive_ptr<caf::actor_control_block>, 6>::operator()' requested here
  return f(std::forward<U>(what));
         ^
.../caf/io/middleman.hpp:167:12: note: in instantiation of function template specialization 'caf::actor_cast<normal::core::OperatorActor, caf::intrusive_ptr<caf::actor_control_block> >' requested here
    return actor_cast<Handle>(std::move(*res));
           ^
.../caf/io/middleman.hpp:175:12: note: in instantiation of function template specialization 'caf::io::middleman::remote_spawn<normal::core::OperatorActor>' requested here
    return remote_spawn<Handle>(nid, std::move(name), std::move(args),
           ^
.../graph/OperatorGraph.cpp:165:12: note: in instantiation of function template specialization 'caf::io::middleman::remote_spawn<normal::core::OperatorActor, long long, std::__1::ratio<1, 1> >' requested here
          .remote_spawn<normal::core::OperatorActor>(node_.value(), "operator", make_message(), remoteSpawnTout);
           ^
.../OperatorActor.h:36:3: note: candidate constructor not viable: no known conversion from 'caf::intrusive_ptr<caf::actor_control_block>::pointer' (aka 'caf::actor_control_block *') to 'caf::actor_config &' for 1st argument
  OperatorActor(caf::actor_config &cfg, std::shared_ptr<Operator> opBehaviour);
  ^
.../OperatorActor.h:25:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided
class OperatorActor : public caf::event_based_actor {
      ^

The constructor of OperatorActor is the following:

OperatorActor::OperatorActor(caf::actor_config &cfg, std::shared_ptr<Operator> opBehaviour) :
    caf::event_based_actor(cfg),
    opBehaviour_(std::move(opBehaviour)) {
  name_ = opBehaviour_->name();
}

which is used when spawn actors locally. It seems not a fit for remote_spawn which I'm unsure how to adjust. Hope this can help :), thanks!

Yifei Yang
@Raining-yyf
In add_actor_type<MyClass, A, B, C>("MyClass"), are A, B, C parameters used in the constructor of MyClass? For the code above I only pass MyClass, probably where the issue is...
Dominik Charousset
@Neverlord
Yes, I think it should read add_actor_type<OperatorActor, std::shared_ptr<Operator>>("operator");. There's also a potential issue with sending a shared_ptr. CAF generally allows this, but be aware that you won't have a good time if Operator is a base type and you'll actually want to serialize/deserialize derived types. That won't work out of the box and you'd have to implement inspect functions that know the full class hierarchy.
Yifei Yang
@Raining-yyf

Thanks, now I change to add_actor_type<OperatorActor, std::shared_ptr<Operator>>("operator");, but the compilation error is still there, which I guess the main error is:

.../OperatorActor.h:36:3: note: candidate constructor not viable: no known conversion from 'caf::intrusive_ptr<caf::actor_control_block>::pointer' (aka 'caf::actor_control_block *') to 'caf::actor_config &' for 1st argument
  OperatorActor(caf::actor_config &cfg, std::shared_ptr<Operator> opBehaviour);
  ^

perhaps my constructor also needs to be modified accordingly, but I'm stuck at this caf::actor_control_block * from the error. :(

Dominik Charousset
@Neverlord
Ah, looking at the compiler error more closely: remote_spawn<normal::core::OperatorActor> isn't OperatorActor your class? The template argument to remote_spawn is the handle type, not the implementation type.
A handle type is either caf::actor for dynamically typed actors or caf::typed_actor<...> for statically typed actors.
If your actor derived event_based_actor, than you need to pass caf::actor here.
Yifei Yang
@Raining-yyf

Yeah OperatorActor is my class deriving event_based_actor, but I'm unsure how to get the handle type from my OperatorActor. I tried OperatorActor::event_based_actor as the following:

auto expectedActorHandle = operatorManager_.lock()->getActorSystem()->middleman()
          .remote_spawn<OperatorActor::event_based_actor>(node_.value(), "operator", make_message(), remoteSpawnTout);

seemed to solve the error of constructor, but it gave 4 other errors, the first one is:

.../caf/actor_cast.hpp:62:36: error: no member named 'has_weak_ptr_semantics' in 'caf::event_based_actor'
  static constexpr bool value = T::has_weak_ptr_semantics;
                                ~~~^
.../caf/actor_cast.hpp:168:44: note: in instantiation of static data member 'caf::(anonymous namespace)::is_weak_ptr<caf::event_based_actor>::value' requested here
  constexpr bool to_weak = is_weak_ptr<T>::value;
                                           ^
.../caf/io/middleman.hpp:167:12: note: in instantiation of function template specialization 'caf::actor_cast<caf::event_based_actor, caf::intrusive_ptr<caf::actor_control_block> >' requested here
    return actor_cast<Handle>(std::move(*res));
           ^
.../caf/io/middleman.hpp:175:12: note: in instantiation of function template specialization 'caf::io::middleman::remote_spawn<caf::event_based_actor>' requested here
    return remote_spawn<Handle>(nid, std::move(name), std::move(args),
           ^
.../OperatorGraph.cpp:166:12: note: in instantiation of function template specialization 'caf::io::middleman::remote_spawn<caf::event_based_actor, long long, std::__1::ratio<1, 1> >' requested here
          .remote_spawn<OperatorActor::event_based_actor>(node_.value(), "operator", make_message(), remoteSpawnTout);

maybe it's not the right way to get the handle type?

Yifei Yang
@Raining-yyf
Btw, as I do as add_actor_type<MyClass, A, B, C>("operator");, where should parameters a, b, c of type A, B, C be passed when calling remote_spawn? like when spawn locally we can actor_system.spawn<MyClass>(a, b, c). remote_spawn has 4 parameters node_id, name, message, timeout, all seems to be fixed.
Dominik Charousset
@Neverlord
The handle type is just actor: .remote_spawn<caf::actor>
Yifei Yang
@Raining-yyf
Thanks it basically works! Should other parameters (i.e. shared_ptr<Operator>) in the constructor of OperatorActor be passed into message (third argument) of remote_spawn, probably using message.load()? or somewhere else?
Dominik Charousset
@Neverlord
Just wrap the constructor arguments into a message via make_message.
Yifei Yang
@Raining-yyf
Thanks, you are awesome! :D
Dominik Charousset
@Neverlord
Glad I could help. 🙂
Dominik Charousset
@Neverlord
Yifei Yang
@Raining-yyf
Sorry to bother again. If I wish to send a message, of which the type is an abstract class (like Operator, where I have classes deriving it).
Should I add_message_type of this abstract Operator, or all deriving types one by one?
And I guess I need to implement inspect for all deriving types, is this correct?
Dominik Charousset
@Neverlord
If at all possible, I'd recommend to switch to a variant-based approach instead. Otherwise, you'd have to keep track of the class hierarchy in your inspect overloads and dispatch accordingly during deserialization. There's not "the way" to do it, though. Depends on whether you are dealing with a sealed class hierarchy (in which case you probably can switch to a variant or at least treat your type as such) or if you want it to remain extensible (then you need some kind of registry/factory interface).
Yifei Yang
@Raining-yyf
thanks!
Yifei Yang
@Raining-yyf
Hey I'm having a hard time deserializing member variables which are shared_ptr, I guess CAF generally allows it right? (guess you mentioned it but seems I didn't fully get it :/). It always yields a nullptr during deserialization at the remote node. Maybe inspect shared_ptr variables need some changes from common objects?
Deserialization of objects works pretty well, but their inspect functions seem not to be used when (de)serializing their shared_ptrs.
Yifei Yang
@Raining-yyf
CAF version I use is 0.17.6, maybe it also makes some difference?
Dominik Charousset
@Neverlord
That's why I'd recommend using a variant-based approach. :)
Also, I would suggest upgrading to 0.18. Any inspect overload you implement now is already obsolete because the inspection API changed.
Virtual dispatching is information hiding, so it naturally is at odds with serialization/deserialization because you need all the object information here.
You probably need some type of enum/index that enumerates all implementation types and then dispatch based on that. Or some kind of type registry if you don't have the full class hierarchy.
Krzysztof Wrzalik
@kyku
Hi, I have a question about program design with actors. Basically I'd like an actor to ping itself periodically to do some internal cleaning, but this should not prevent the actor from being destroyed if needed. Now if I do this the obvious way with delayed_send(), there is some reference being held on the actor and it won't go away until the ping message is delivered and dispatched. Sure I can do this with some additional monitoring actor but send seems redundant.
Dominik Charousset
@Neverlord
Messages must keep a strong reference to an actor, so there's no obvious way with the current scheduled/delayed message API. Right now a separate actor is probably the only way. This could be a starting point:
struct tick_actor_state {
  tick_actor_state(caf::event_based_actor* self, caf::actor worker)
    : self(self) hdl(caf::actor_cast<caf::actor_addr>(worker)) {
    // nop
  }

  caf::behavior make_behavior() {
    using std::chrono_literals;
    self->scheduled_send(self, 1s, caf::tick_atom_v);
    return {
      [](caf::tick_atom) {
        if (auto sref = caf::actor_cast<caf::actor>(hdl)) {
          self->send(sref, caf::tick_atom_v);
          self->scheduled_send(self, 1s, caf::tick_atom_v);
        }
      }
    };
  }

  caf::event_based_actor* self;
  caf::actor_addr hdl;
};
Krzysztof Wrzalik
@kyku
Thanks for the tip, Dominik!
Dominik Charousset
@Neverlord
But please feel free to open an issue to add something like dealyed_weak_message to the API to do this with less friction.
Krzysztof Wrzalik
@kyku
Sure, I'll add this later today.
Dominik Charousset
@Neverlord
Ok. Untested code, of course, but I hope it helps for the time being. :)
Yifei Yang
@Raining-yyf
Thanks! will upgrade then. For the variant-based approach, sorry I didn't quite get it, could you please explain a little more, or just a simple start point that I can follow? :) Currently I seem to keep track of full class hierarchy (including member variables of other classes) and dispatch serialization in that way...
Dominik Charousset
@Neverlord
@Raining-yyf here you go: https://github.com/actor-framework/actor-framework/blob/43bdccb0359a61843b93304f7b856c522ac01d3a/examples/custom_type/custom_types_4.cpp
The example is a bit contrived, because one might as well use variant<none_t, circle, rectangle>, but it should give you a starting point.
Yifei Yang
@Raining-yyf
That's super helpful!! Thanks! :D
Matt Youill
@matt.youill_gitlab
Hi, another question on serialization. Say I have a message class containing a field of bytes (e.g. void*) would this be recognized by caf's type inspection system? If not what would be the best way to send/receive it?
Dominik Charousset
@Neverlord
There's not much CAF can do with a void*. CAF uses vector<byte> or span<byte> to represent "bunch of bytes".
Dominik Charousset
@Neverlord
@Raining-yyf FYI, the old link no longer works, but the example found its way to master now: https://github.com/actor-framework/actor-framework/blob/master/examples/custom_type/custom_types_4.cpp
Yifei Yang
@Raining-yyf
Got it, thanks!
Dominik Lohmann
@dominiklohmann
What are the implications of the error activate called on a terminated actor (CAF 0.17.6)? I see it occasionally, and am wondering what could cause it and how important of an error it is.
Dominik Charousset
@Neverlord
I've also seen them pop up every now and then. It shouldn't happen, but CAF at least detects and gracefully handles this case. We should fix it eventually, though.
Still happens with 0.18, btw.
Dominik Lohmann
@dominiklohmann
If CAF handles it gracefully, can you make that error a warning instead and maybe make it a bit more verbose such that it is clear that while unexpected, it was gracefully handled?
Dominik Charousset
@Neverlord
I wouldn't object to making it a warning instead.
Dominik Charousset
@Neverlord
We have a new article online: https://cafcademy.com/articles/implementing-actors-part-1. 🙂