LCOV - code coverage report
Current view: top level - include/hpactor/core - actor_system.hpp (source / functions) Coverage Total Hit
Test: HPActor Coverage Lines: 87.7 % 73 64
Test Date: 2026-05-20 02:24:49 Functions: 87.5 % 40 35
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright 2026 HPActor Contributors
       2                 :             : //
       3                 :             : // Licensed under the Apache License, Version 2.0 (the "License");
       4                 :             : // you may not use this file except in compliance with the License.
       5                 :             : // You may obtain a copy of the License at
       6                 :             : //
       7                 :             : //     http://www.apache.org/licenses/LICENSE-2.0
       8                 :             : //
       9                 :             : // Unless required by applicable law or agreed to in writing, software
      10                 :             : // distributed under the License is distributed on an "AS IS" BASIS,
      11                 :             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :             : // See the License for the specific language governing permissions and
      13                 :             : // limitations under the License.
      14                 :             : 
      15                 :             : #pragma once
      16                 :             : 
      17                 :             : #include <hpactor/actor/abstract_actor.hpp>
      18                 :             : #include <hpactor/actor/actor_context.hpp>
      19                 :             : #include <hpactor/actor/drain_config.hpp>
      20                 :             : #include <hpactor/actor/lifecycle_actor.hpp>
      21                 :             : #include <hpactor/cli/cli_config.hpp>
      22                 :             : #include <hpactor/config/topology_model.hpp>
      23                 :             : #include <hpactor/core/actor_registry.hpp>
      24                 :             : #include <hpactor/core/mailbox.hpp>
      25                 :             : #include <hpactor/core/proto_type_registry.hpp>
      26                 :             : #include <hpactor/hpactor_config.hpp>
      27                 :             : #include <hpactor/log/log_config.hpp>
      28                 :             : #include <hpactor/log/log_field.hpp>
      29                 :             : #include <hpactor/log/logger.hpp>
      30                 :             : #include <hpactor/mailbox/dead_letter_queue.hpp>
      31                 :             : #include <hpactor/mailbox/mpsc_actor_mailbox.hpp>
      32                 :             : #include <hpactor/metrics/metrics_config.hpp>
      33                 :             : #include <hpactor/metrics/metrics_event.hpp>
      34                 :             : #include <hpactor/metrics/metrics_ring_buffer.hpp>
      35                 :             : #include <hpactor/net/actor_location_cache.hpp>
      36                 :             : #include <hpactor/net/frame.hpp>
      37                 :             : #include <hpactor/net/gossip_membership.hpp>
      38                 :             : #include <hpactor/net/http_client.hpp>
      39                 :             : #include <hpactor/net/registrar.hpp>
      40                 :             : #include <hpactor/net/service_discovery.hpp>
      41                 :             : #include <hpactor/net/static_discovery.hpp>
      42                 :             : #include <hpactor/net/tcp_transport.hpp>
      43                 :             : #include <hpactor/ref/actor_ref.hpp>
      44                 :             : #include <hpactor/rpc/rpc_channel.hpp>
      45                 :             : #include <hpactor/sched/dispatch_policy.hpp>
      46                 :             : #include <hpactor/sched/scheduler.hpp>
      47                 :             : #include <hpactor/tracing/trace_config.hpp>
      48                 :             : #include <hpactor/tracing/trace_manager.hpp>
      49                 :             : #include <hpactor/types/types.hpp>
      50                 :             : 
      51                 :             : #include <atomic>
      52                 :             : #include <chrono>
      53                 :             : #include <memory>
      54                 :             : #include <mutex>
      55                 :             : #include <thread>
      56                 :             : #include <unordered_map>
      57                 :             : 
      58                 :             : namespace hpactor {
      59                 :             : 
      60                 :             : // Forward declarations
      61                 :             : class AsyncActor;
      62                 :             : class ActorTypeRegistry;
      63                 :             : 
      64                 :             : namespace log {
      65                 :             : class LogManager;
      66                 :             : class Logger;
      67                 :             : } // namespace log
      68                 :             : 
      69                 :             : namespace cli {
      70                 :             : class CliActor;
      71                 :             : } // namespace cli
      72                 :             : 
      73                 :             : // Scheduler interface forward declaration
      74                 :             : namespace sched {
      75                 :             : class IScheduler;
      76                 :             : class HybridScheduler;
      77                 :             : } // namespace sched
      78                 :             : 
      79                 :             : // -----------------------------------------------------------------------------
      80                 :             : // MailboxDefaults - system-wide default mailbox configuration
      81                 :             : // -----------------------------------------------------------------------------
      82                 :             : struct MailboxDefaults {
      83                 :             : #define HPACTOR_MAILBOX_FIELD(name, type, toml, def) type name{def};
      84                 :             : #include <hpactor/config/mailbox_fields.def>
      85                 :             : #undef HPACTOR_MAILBOX_FIELD
      86                 :             : };
      87                 :             : 
      88                 :             : // -----------------------------------------------------------------------------
      89                 :             : // Config - configuration for ActorSystem
      90                 :             : // -----------------------------------------------------------------------------
      91                 :             : struct Config {
      92                 :             : // ── Shared system fields (generated from config/system_fields.def) ──
      93                 :             : #define HPACTOR_SYSTEM_FIELD(name, type, toml, def) type name{def};
      94                 :             : #include <hpactor/config/system_fields.def>
      95                 :             : #undef HPACTOR_SYSTEM_FIELD
      96                 :             : 
      97                 :             :     // ── Config-only fields ──
      98                 :             :     EndPoint endpoint = LocalEndpoint;
      99                 :             : 
     100                 :             :     // TLS and pool config (used if enable_network=true)
     101                 :             :     net::TlsConfig tls = {};
     102                 :             :     net::PoolConfig pool = {};
     103                 :             :     net::RegistrarConfig registrar = {};
     104                 :             : 
     105                 :             :     // HTTP subsystem (requires enable_network = true)
     106                 :             :     bool enable_http_client = false;
     107                 :             : 
     108                 :             :     // Coroutine scheduling (requires HPACTOR_SUPPORT_COROUTINES=1 at compile
     109                 :             :     // time) When true, actors use coroutine-based execution instead of
     110                 :             :     // behavior-based. Default: false (behavior-based scheduling).
     111                 :             :     bool use_coroutines = false;
     112                 :             : 
     113                 :             :     // CLI configuration
     114                 :             :     cli::CliConfig cli;
     115                 :             : 
     116                 :             :     // Service discovery backend. nullptr = auto-select based on enable_network
     117                 :             :     // and registrar config (backward compatible).
     118                 :             :     std::shared_ptr<net::IServiceDiscovery> service_discovery = nullptr;
     119                 :             : 
     120                 :             :     // Gossip configuration. Used when creating GossipMembership internally.
     121                 :             :     net::GossipConfig gossip = {};
     122                 :             : 
     123                 :             :     // Mailbox defaults — applied to every actor spawned via this system
     124                 :             :     MailboxDefaults mailbox;
     125                 :             : 
     126                 :             :     // Dead-letter queue configuration
     127                 :             :     mailbox::DeadLetterConfig dead_letters;
     128                 :             : 
     129                 :             :     // Shutdown configuration
     130                 :             :     DrainConfig shutdown_drain{DrainPolicy::Drain,
     131                 :             :                                std::chrono::milliseconds{30'000}};
     132                 :             :     uint32_t ingress_timeout_ms{5000};
     133                 :             :     uint32_t cluster_leave_timeout_ms{10000};
     134                 :             :     bool shutdown_force_after_timeout{true};
     135                 :             : 
     136                 :             :     // Timer backend selection
     137                 :             :     sched::TimerBackend timer_backend = sched::TimerBackend::TimingWheel;
     138                 :             : 
     139                 :             :     // Start scheduler workers in paused state (for deterministic testing).
     140                 :             :     // When true, workers are created but blocked until resume_workers() is
     141                 :             :     // called.
     142                 :             :     bool scheduler_start_paused = false;
     143                 :             : 
     144                 :             :     // Distributed tracing configuration
     145                 :             :     tracing::TraceConfig tracing;
     146                 :             : };
     147                 :             : 
     148                 :             : // -----------------------------------------------------------------------------
     149                 :             : // ActorTypeDef - definition of an actor type
     150                 :             : // -----------------------------------------------------------------------------
     151                 :             : struct ActorTypeDef {
     152                 :             :     std::string name;
     153                 :             :     ActorType id;
     154                 :             : };
     155                 :             : 
     156                 :             : // Shutdown phase enumeration
     157                 :             : enum class ShutdownPhase : uint8_t {
     158                 :             :     Running,
     159                 :             :     DrainingIngress,
     160                 :             :     DrainingActors,
     161                 :             :     LeavingCluster,
     162                 :             :     FlushingTelemetry,
     163                 :             :     Stopped,
     164                 :             :     ForcedStop,
     165                 :             : };
     166                 :             : 
     167                 :             : struct ShutdownOptions {
     168                 :           0 :     std::chrono::milliseconds ingress_timeout{5'000};
     169                 :           0 :     std::chrono::milliseconds actor_drain_timeout{30'000};
     170                 :           0 :     std::chrono::milliseconds cluster_leave_timeout{10'000};
     171                 :             :     bool force_after_timeout{true};
     172                 :             : };
     173                 :             : 
     174                 :             : // -----------------------------------------------------------------------------
     175                 :             : // ActorSystem - the actor environment containing schedulers, registry, etc.
     176                 :             : // -----------------------------------------------------------------------------
     177                 :             : class ActorSystem {
     178                 :             :   public:
     179                 :             :     explicit ActorSystem(const Config& config);
     180                 :             :     ~ActorSystem();
     181                 :             : 
     182                 :             :     // Non-copyable, non-movable
     183                 :             :     ActorSystem(const ActorSystem&) = delete;
     184                 :             :     ActorSystem& operator=(const ActorSystem&) = delete;
     185                 :             :     ActorSystem(ActorSystem&&) = delete;
     186                 :             :     ActorSystem& operator=(ActorSystem&&) = delete;
     187                 :             : 
     188                 :             :     // Spawn actors at system level
     189                 :             :     template <typename T, typename... Args> Actor spawn(Args&&... args);
     190                 :             : 
     191                 :             :     // Spawn a pre-constructed actor with configuration from ActorDef.
     192                 :             :     // Used by BootstrapEngine for TOML-based topology bootstrapping.
     193                 :             :     Actor spawn_configured(std::shared_ptr<AbstractActor> actor,
     194                 :             :                            const struct config::ActorDef& def);
     195                 :             : 
     196                 :             :     // Load topology from TOML file (convenience entry point)
     197                 :             :     result<void> load_topology(const std::string& toml_path);
     198                 :             : 
     199                 :             :     // Actor registry
     200                 :             :     void register_actor(const std::string& name, Actor actor);
     201                 :             :     Actor resolve_actor(const std::string& name);
     202                 :             :     void unregister_actor(const std::string& name);
     203                 :             : 
     204                 :             :     // Actor type registration
     205                 :             :     void register_actor_type(const ActorTypeDef& def);
     206                 :             :     ActorTypeDef get_actor_type(ActorType type) const;
     207                 :             : 
     208                 :             :     // Clock
     209                 :          32 :     Clock& clock() {
     210                 :          32 :         return clock_;
     211                 :             :     }
     212                 :             : 
     213                 :             :     // System actor
     214                 :             :     Actor system_actor() {
     215                 :             :         return system_actor_;
     216                 :             :     }
     217                 :             : 
     218                 :             :     // Registry access
     219                 :           9 :     actor_registry& registry() {
     220                 :           9 :         return registry_;
     221                 :             :     }
     222                 :             : 
     223                 :             :     // Proto type registry
     224                 :           0 :     ProtoTypeRegistry& proto_registry() {
     225                 :           0 :         return proto_registry_;
     226                 :             :     }
     227                 :             :     const ProtoTypeRegistry& proto_registry() const {
     228                 :             :         return proto_registry_;
     229                 :             :     }
     230                 :             : 
     231                 :             :     // Node ID
     232                 :          31 :     EndPoint endpoint() const {
     233                 :          31 :         return endpoint_;
     234                 :             :     }
     235                 :             : 
     236                 :             :     // Check if actor system is running
     237                 :           2 :     bool is_running() const {
     238                 :           2 :         return running_.load(std::memory_order_acquire);
     239                 :             :     }
     240                 :             : 
     241                 :             :     // Get scheduler for direct scheduling operations
     242                 :          31 :     sched::IScheduler* scheduler() {
     243                 :          31 :         return scheduler_.get();
     244                 :             :     }
     245                 :             : 
     246                 :             :     // Runtime coroutine toggle (requires HPACTOR_SUPPORT_COROUTINES=1 at
     247                 :             :     // compile time). Default: false (behavior-based scheduling).
     248                 :         353 :     bool use_coroutines() const {
     249                 :         353 :         return config_.use_coroutines;
     250                 :             :     }
     251                 :             : 
     252                 :             :     // RPC channel for remote calls
     253                 :           0 :     RpcChannel& rpc_channel() {
     254                 :           0 :         return *rpc_channel_;
     255                 :             :     }
     256                 :             : 
     257                 :             :     // HTTP client for outbound HTTP requests
     258                 :           0 :     net::HttpClient& http_client() {
     259                 :           0 :         return *http_client_;
     260                 :             :     }
     261                 :             : 
     262                 :             :     // Distributed tracing
     263                 :         690 :     tracing::TraceManager* trace_manager() noexcept {
     264                 :         690 :         return trace_manager_.get();
     265                 :             :     }
     266                 :             : 
     267                 :             :     const tracing::TraceManager* trace_manager() const noexcept {
     268                 :             :         return trace_manager_.get();
     269                 :             :     }
     270                 :             : 
     271                 :             :     void apply_tracing_config(const tracing::TraceConfig& config);
     272                 :             : 
     273                 :             :     // Internal actor lookup (used by scheduler)
     274                 :             :     std::shared_ptr<AbstractActor> get_actor(ActorId id);
     275                 :             : 
     276                 :             :     // Get metrics ring buffer (nullptr if metrics disabled)
     277                 :           4 :     auto* metrics_ring_buffer() const {
     278                 :           4 :         return metrics_ring_buffer_.get();
     279                 :             :     }
     280                 :             : 
     281                 :             :     // Get CLI actor (nullptr if CLI disabled or not yet spawned)
     282                 :             :     cli::CliActor* cli_actor() const;
     283                 :             : 
     284                 :             :     // Get actor's mailbox (used by scheduler)
     285                 :             :     mailbox::MPSCActorMailbox<TypedMessage>* get_mailbox(ActorId id);
     286                 :             : 
     287                 :             :     // Get the number of live actors in this system
     288                 :             :     size_t actor_count() const;
     289                 :             : 
     290                 :             :     // Enumerate all actors. Callback receives (ActorId, AbstractActor&).
     291                 :             :     // The callback must not spawn or kill actors (lock is held).
     292                 :             :     void for_each_actor(std::function<void(ActorId, AbstractActor&)> callback) const;
     293                 :             : 
     294                 :             :     // Deliver message to local actor
     295                 :             :     void deliver_local(ActorId target, TypedMessage msg);
     296                 :             : 
     297                 :             :     // Deliver message to local actor with priority and deadline for scheduling
     298                 :             :     // priority: 0-3 (0 = highest)
     299                 :             :     // deadline_ns: absolute deadline in nanoseconds (INT64_MAX = no deadline)
     300                 :             :     void deliver_local(ActorId target, TypedMessage msg, uint8_t priority,
     301                 :             :                        int64_t deadline_ns);
     302                 :             : 
     303                 :             :     // Bounded admission delivery — returns an EnqueueResult describing the
     304                 :             :     // outcome. Returns ActorNotFound when the target actor does not exist,
     305                 :             :     // Rejected when the mailbox is at hard capacity.
     306                 :             :     mailbox::EnqueueResult
     307                 :             :     try_deliver_local(ActorId target, TypedMessage msg, uint8_t priority = 0,
     308                 :             :                       int64_t deadline_ns = INT64_MAX,
     309                 :             :                       mailbox::DeliveryOptions options = {});
     310                 :             : 
     311                 :             :     // Dead-letter queue
     312                 :             :     bool dead_letter(mailbox::DeadLetterRecord record) noexcept;
     313                 :             :     mailbox::DeadLetterQueueSnapshot dead_letter_snapshot() const noexcept;
     314                 :             :     bool pop_dead_letter(mailbox::DeadLetterRecord& out) noexcept;
     315                 :             : 
     316                 :             :     // Build a MailboxConfig from system-wide defaults in Config::mailbox.
     317                 :             :     mailbox::MailboxConfig mailbox_config_for_spawn() const;
     318                 :             : 
     319                 :             :     // Build a MailboxConfig for a specific ActorDef, falling back to system
     320                 :             :     // defaults when ActorDef fields are zero.
     321                 :             :     mailbox::MailboxConfig
     322                 :             :     mailbox_config_for_actor_def(const config::ActorDef& def) const;
     323                 :             : 
     324                 :             :     // Deliver a remote message (from WireFrame) to the target actor's mailbox.
     325                 :             :     // Bridges the transport layer to the unified deliver_local() sink.
     326                 :             :     void deliver_remote(const net::WireFrame& frame);
     327                 :             : 
     328                 :             :     // Called by IServiceDiscovery when a remote node becomes unreachable.
     329                 :             :     // Finds all actors linked to the dead endpoint and delivers DownMsg.
     330                 :             :     void on_node_dead(EndPoint dead_ep);
     331                 :             : 
     332                 :             :     // Emit a backpressure signal to the sender actor, delivered through
     333                 :             :     // the sender's ActorContext::handle_backpressure() handler.
     334                 :             :     void signal_backpressure(const mailbox::BackpressureSignal& signal);
     335                 :             : 
     336                 :             :     // Enqueue an I/O completion to be delivered to an actor
     337                 :             :     // Called by EventLoop when async operations complete
     338                 :             :     void enqueue_completion(net::OpCompletion completion);
     339                 :             : 
     340                 :             :     // Network access
     341                 :             :     net::Transport* transport() {
     342                 :             :         return transport_.get();
     343                 :             :     }
     344                 :             : 
     345                 :             :     // Return the transport for sending to a remote endpoint.
     346                 :             :     // Currently returns the single transport_ for all remote endpoints, since
     347                 :             :     // TcpTransport handles per-endpoint routing internally via its pools_ map.
     348                 :             :     // The endpoint parameter is reserved for future multi-transport scenarios.
     349                 :             :     // Returns nullptr if networking is not enabled.
     350                 :             :     net::Transport* get_transport_for(const EndPoint& endpoint);
     351                 :             : 
     352                 :             :     net::UdpRegistrar* registrar() {
     353                 :             :         return registrar_.get();
     354                 :             :     }
     355                 :             : 
     356                 :             :     // Remote actor spawning (main/non-actor context only)
     357                 :             :     result<ActorRef>
     358                 :             :     spawn_remote(const std::string& node_name, const std::string& actor_type,
     359                 :             :                  const StreamBuffer& args);
     360                 :             : 
     361                 :             :     AsyncActor
     362                 :             :     spawn_remote_async(const std::string& node_name,
     363                 :             :                        const std::string& actor_type, const StreamBuffer& args);
     364                 :             : 
     365                 :             :     // Actor type registry for remote spawning
     366                 :             :     ActorTypeRegistry& actor_type_registry() {
     367                 :             :         return *actor_type_registry_;
     368                 :             :     }
     369                 :             :     const ActorTypeRegistry& actor_type_registry() const {
     370                 :             :         return *actor_type_registry_;
     371                 :             :     }
     372                 :             : 
     373                 :             :     // ── Shutdown ───────────────────────────────────────────────────────────
     374                 :             : 
     375                 :             :     // Node shutdown — drives the full phase machine.
     376                 :             :     // Overload with no arguments uses default ShutdownOptions{}.
     377                 :             :     result<void> shutdown();
     378                 :             :     result<void> shutdown(const ShutdownOptions& opts);
     379                 :             : 
     380                 :             :     // Current shutdown phase
     381                 :             :     ShutdownPhase shutdown_phase() const noexcept;
     382                 :             : 
     383                 :             :     // Health/readiness gating
     384                 :             :     bool is_ready() const noexcept;
     385                 :             :     bool is_draining() const noexcept;
     386                 :             : 
     387                 :             :     // Per-actor drain config override (for admin/CLI use)
     388                 :             :     void set_drain_config(ActorId target, DrainConfig cfg);
     389                 :             : 
     390                 :             :   private:
     391                 :             :     Config config_;
     392                 :             :     EndPoint endpoint_;
     393                 :             :     Clock clock_;
     394                 :             :     actor_registry registry_;
     395                 :             :     std::unordered_map<ActorType, ActorTypeDef> actor_types_;
     396                 :             :     Actor system_actor_;
     397                 :             : 
     398                 :             :     // Actor registry - maps ActorId to actor instance
     399                 :             :     std::unordered_map<ActorId, std::shared_ptr<AbstractActor>> actors_;
     400                 :             :     mutable std::mutex actors_mutex_;
     401                 :             : 
     402                 :             :     // Actor mailboxes - maps ActorId to mailbox
     403                 :             :     std::unordered_map<ActorId, std::unique_ptr<mailbox::MPSCActorMailbox<TypedMessage>>> mailboxes_;
     404                 :             :     std::mutex mailboxes_mutex_;
     405                 :             : 
     406                 :             :     // Actor contexts - maps ActorId to context
     407                 :             :     std::unordered_map<ActorId, std::unique_ptr<ActorContext>> actor_contexts_;
     408                 :             :     std::mutex actor_contexts_mutex_;
     409                 :             : 
     410                 :             :     // Actor ID generator
     411                 :             :     std::atomic<uint64_t> next_actor_id_{1};
     412                 :             : 
     413                 :             :     // Running flag for network thread loop
     414                 :             :     std::atomic<bool> running_{true};
     415                 :             : 
     416                 :             :     // Shutdown state
     417                 :             :     std::atomic<ShutdownPhase> shutdown_phase_{ShutdownPhase::Running};
     418                 :             :     std::atomic<bool> is_ready_{true};
     419                 :             : 
     420                 :             :     // Scheduler
     421                 :             :     std::unique_ptr<sched::IScheduler> scheduler_;
     422                 :             : 
     423                 :             :     // Network components (owned)
     424                 :             :     std::unique_ptr<net::TcpTransport> transport_;
     425                 :             :     std::shared_ptr<net::UdpRegistrar> registrar_;
     426                 :             :     std::shared_ptr<net::IServiceDiscovery> discovery_;
     427                 :             :     std::shared_ptr<net::ActorLocationCache> location_cache_;
     428                 :             :     uint64_t cache_purge_timer_ = 0;
     429                 :             :     std::unique_ptr<net::EventLoop> network_loop_;
     430                 :             :     std::thread network_thread_;
     431                 :             : 
     432                 :             :     // Actor type registry for remote spawning (owned via pointer to avoid
     433                 :             :     // circular dep)
     434                 :             :     std::unique_ptr<ActorTypeRegistry> actor_type_registry_;
     435                 :             : 
     436                 :             :     // RPC channel for remote calls (after transport_ creation)
     437                 :             :     std::unique_ptr<RpcChannel> rpc_channel_;
     438                 :             :     // HTTP client for outbound HTTP calls
     439                 :             :     std::unique_ptr<net::HttpClient> http_client_;
     440                 :             : 
     441                 :             :     // HTTP gateway actor (DaemonActor, spawned when enable_http_gateway = true)
     442                 :             :     Actor http_gateway_actor_{nullptr};
     443                 :             : 
     444                 :             :     // CLI actor (DaemonActor, spawned when cli.enabled = true)
     445                 :             :     std::shared_ptr<cli::CliActor> cli_actor_;
     446                 :             : 
     447                 :             :     // Metrics configuration and ring buffer
     448                 :             :     metrics::MetricsConfig metrics_config_;
     449                 :             :     std::shared_ptr<metrics::MpscRingBuffer<metrics::MetricEvent>> metrics_ring_buffer_;
     450                 :             : 
     451                 :             :     // Logging subsystem
     452                 :             :     log::LogConfig logging_config_;
     453                 :             :     std::unique_ptr<log::LogManager> log_manager_;
     454                 :             :     log::Logger* logger_ = nullptr;
     455                 :             : 
     456                 :             :     // Dead-letter queue
     457                 :             :     std::unique_ptr<mailbox::DeadLetterQueue> dead_letters_;
     458                 :             : 
     459                 :             :     // Tracing subsystem
     460                 :             :     tracing::TraceConfig tracing_config_;
     461                 :             :     std::unique_ptr<tracing::TraceManager> trace_manager_;
     462                 :             : 
     463                 :             :     // Proto type registry for protobuf message serialization
     464                 :             :     ProtoTypeRegistry proto_registry_;
     465                 :             : 
     466                 :             :     // Pending remote spawns awaiting response
     467                 :             :     std::unordered_map<uint64_t, std::shared_ptr<AsyncActor>> pending_spawns_;
     468                 :             :     std::mutex pending_spawns_mutex_;
     469                 :             : };
     470                 :             : 
     471                 :             : // -----------------------------------------------------------------------------
     472                 :             : // Template implementations
     473                 :             : // -----------------------------------------------------------------------------
     474                 :             : 
     475                 :             : template <typename T, typename... Args>
     476                 :         108 : Actor ActorSystem::spawn(Args&&... args) {
     477                 :         216 :     ActorId id(next_actor_id_.fetch_add(1));
     478                 :         108 :     auto actor = std::make_shared<T>(nullptr, *this, std::forward<Args>(args)...);
     479                 :         108 :     actor->set_address(ActorAddress(endpoint_, actor->type(), id, 0));
     480                 :             :     if constexpr (requires { T::kActorTypeName; }) {
     481                 :             :         actor->set_type_name(T::kActorTypeName);
     482                 :             :     } else {
     483                 :         216 :         actor->set_type_name("unknown");
     484                 :             :     }
     485                 :             : 
     486                 :             :     {
     487                 :         108 :         std::lock_guard<std::mutex> lock(actors_mutex_);
     488                 :         108 :         actors_.emplace(id, actor);
     489                 :         108 :     }
     490                 :             : 
     491                 :             :     // Create mailbox
     492                 :             :     {
     493                 :         108 :         std::lock_guard<std::mutex> lock(mailboxes_mutex_);
     494                 :         108 :         mailboxes_.emplace(
     495                 :             :             id, std::make_unique<mailbox::MPSCActorMailbox<TypedMessage>>(
     496                 :         108 :                     id, scheduler_.get(), mailbox_config_for_spawn()));
     497                 :         108 :     }
     498                 :             : 
     499                 :             :     // Create actor context and set it on the actor
     500                 :         108 :     auto actor_ctx = std::make_unique<ActorContext>(Actor(actor), this);
     501                 :         108 :     actor->set_context(actor_ctx.get());
     502                 :         108 :     actor_contexts_.emplace(id, std::move(actor_ctx));
     503                 :             : 
     504                 :             :     // Set scheduler and mailbox on actor
     505                 :         108 :     actor->set_scheduler(scheduler_.get());
     506                 :         108 :     actor->set_mailbox(mailboxes_[id].get());
     507                 :             : 
     508                 :             :     // Wire metrics ring buffer to actor and mailbox
     509                 :         108 :     if (metrics_ring_buffer_) [[unlikely]] {
     510                 :         108 :         auto* mbox = mailboxes_[id].get();
     511                 :         108 :         mbox->set_metrics_ring_buffer(metrics_ring_buffer_.get());
     512                 :         108 :         actor->set_metrics_ring_buffer(metrics_ring_buffer_.get());
     513                 :             :     }
     514                 :             : 
     515                 :             :     // Wire logger to actor and mailbox
     516                 :         108 :     if (logger_) [[unlikely]] {
     517                 :         108 :         auto* mbox = mailboxes_[id].get();
     518                 :         108 :         mbox->set_logger(logger_);
     519                 :         108 :         actor->set_logger(logger_);
     520                 :             :     }
     521                 :             : 
     522                 :             :     // Register with scheduler based on dispatch policy.
     523                 :             :     // Cooperative actors go onto the work-stealing pool. Dedicated actors
     524                 :             :     // are registered with the scheduler but NOT placed on the cooperative
     525                 :             :     // pool — they manage their own threads or use DedicatedThreadPool.
     526                 :         108 :     switch (actor->dispatch_policy()) {
     527                 :          97 :         case sched::DispatchPolicy::Cooperative:
     528                 :          97 :             scheduler_->notify_ready(id, 0, INT64_MAX);
     529                 :          97 :             break;
     530                 :           9 :         case sched::DispatchPolicy::DedicatedThread:
     531                 :          18 :             scheduler_->register_dedicated_thread(
     532                 :           9 :                 id, actor->dispatch_hints().cpu_affinity);
     533                 :           9 :             break;
     534                 :           2 :         case sched::DispatchPolicy::DedicatedPool:
     535                 :           2 :             scheduler_->register_dedicated_pool(id, actor->dispatch_hints().pool_size);
     536                 :           2 :             break;
     537                 :             :     }
     538                 :             : 
     539                 :             :     // Activate the actor (DaemonActor starts its thread here, etc.)
     540                 :         108 :     actor->on_activate();
     541                 :             : 
     542                 :             :     // Transition lifecycle to ACTIVE if actor has lifecycle management
     543                 :         108 :     if (auto* lc = actor->as_lifecycle()) {
     544                 :          25 :         lc->transition(LifecycleState::kActive);
     545                 :             :     }
     546                 :             : 
     547                 :         108 :     HPACTOR_LOG_INFO(log::LogCategory::kActor, id,
     548                 :             :                      static_cast<uint32_t>(log::LogEventId::kActorSpawned),
     549                 :             :                      "actor spawned",
     550                 :             :                      log::field_lit("type", actor->type_name().data()));
     551                 :             : 
     552                 :         108 :     if (metrics_ring_buffer_) [[unlikely]] {
     553                 :         108 :         metrics::MetricEvent evt{};
     554                 :         108 :         evt.actor_id = id;
     555                 :         108 :         evt.event_type = metrics::MetricEventType::kActorSpawned;
     556                 :         108 :         evt.value_hi = 1;
     557                 :         108 :         metrics_ring_buffer_->try_push(evt);
     558                 :             :     }
     559                 :             : 
     560                 :         108 :     return Actor(actor);
     561                 :         108 : }
     562                 :             : 
     563                 :             : } // namespace hpactor
        

Generated by: LCOV version 2.0-1