Skip to content

Skynet Comparison ​

Shield draws on Skynet's service model, but the goal is neither to clone Skynet nor to grow into a general distributed framework.

For full runtime semantics see the Runtime Semantics Decisions.

Similarities ​

  • Services are the basic unit of execution.
  • Lua carries the main business logic.
  • send means asynchronous message.
  • call means request-response.
  • Timers and a lightweight service lifecycle are core capabilities.

Differences ​

DimensionSkynetShield refactoring target
Runtime languageC + LuaC++23 + Lua
Actor foundationhand-writtenCAF internal implementation
User APIskynet.*shield.*
ConfigurationLua configYAML declarative config
PlatformsUnix-like primarilyWindows / macOS / Linux
Current scopesingle process + cluster capabilitysingle node first, cluster as an official optional module

API Mapping ​

lua
-- Skynet
skynet.send(address, "lua", msg_type, ...)
local response = skynet.call(address, "lua", msg_type, ...)

-- Shield target
shield.send("service_name", method, data)
local ok, response = shield.call_timeout(timeout_ms, "service_name", method, data)
lua
-- Skynet
skynet.timeout(100, function() ... end)

-- Shield target
shield.timer_once(100, function() ... end)

CAF and Skynet Semantics ​

Shield's goal is not to re-implement Skynet's underlying actor runtime, but to let CAF carry the machinery layer and then fill in Skynet-like service semantics.

LayerSkynetCAFShield decision
actor schedulingSkynet hand-writtenCAF scheduleruse CAF
actor/messageSkynet service/messageCAF actor/messageuse CAF, hide the handle
async sendskynet.sendsend / anon_sendwrap as shield.send
sync callskynet.call + Lua coroutine yieldrequest + continuationwrap as coroutine-aware shield.call
timerskynet.timeoutschedule / delayed sendwrap as shield.timer_once / shield.timer
service namehandle/name serviceactor handle / registry mechanismShield maintains its own service registry
Lua serviceLua script serviceCAF does not handle Luaimplemented by shield_lua
remote actorharbor/clustermiddleman publish/connectnot in core; belongs to shield_cluster

ID and Cluster Address Differences ​

Skynet's actor address can use the compact model of a high-bit cluster/harbor id and a low-bit local handle. Shield keeps this idea but does not make the bit layout part of the public ServiceId contract.

Shield decision:

cpp
using ServiceId = uint64_t; // local service id
using NodeId = uint32_t;    // node id

struct ServiceAddress {
  NodeId node;
  ServiceId id;
};

Different nodes may have identical local ServiceIds; the global routing identity is determined by {node_id, node_epoch, service_id}. This avoids welding the public API to a fixed bit layout and also handles stale messages mis-delivered after a node restarts.

Key Difference ​

CAF covers machinery; it does not cover Skynet's Lua service experience.

The most critical difference is call:

text
Skynet call:
  send request → session binds the current Lua coroutine → yield → response arrives → resume

CAF request:
  send request → continuation / await / receive → C++ actor processes the response

Shield call:
  uses the CAF request mechanism
  but exposes Skynet-like coroutine suspension semantics to Lua

Therefore shield.call must neither directly expose the CAF request nor do a thread-blocking wait inside Lua. The correct design is to suspend the current Lua coroutine while keeping the actor runtime free to keep scheduling other messages.

Semantics CAF Covers vs. What Shield Adds ​

CAF handles the actor machinery (spawn/quit, send/request, schedule, scheduler); Shield exposes game-server semantics on top of it. CAF does not directly provide Skynet-style Lua runtime semantics; Shield must add:

Shield semanticsWhy CAF does not provide it directly
service name registryCAF primarily operates on actor handles, not game service names
Lua coroutine pending/resumethe CAF request knows nothing about Lua coroutines
the synchronous style of shield.callCAF is a C++ continuation/request mechanism
Lua service lifecycleCAF knows nothing about Lua scripts and init/message/exit
Lua table payloadsCAF leans toward the C++ type system
uniqueservice/queryservice-style semanticsthis is Shield's service model, not CAF machinery

No CAF exposure: Lua and user-side C++ extensions should not include CAF headers or manipulate CAF actor handles directly. For further discussion of CAF as an implementation detail see Core Design Principles.

This section was merged from the former caf-mapping.md (deleted).

What Shield Does Not Cover ​

  • The Skynet harbor cluster model does not directly enter core; multi-node capability belongs to shield_cluster.
  • The snax framework.
  • Shared-data mechanisms such as sharedata / stm.
  • A built-in service discovery framework.
  • Prometheus / health check / plugin system as core.

The current refactoring prioritizes making single-node services, messages, networking, and the Lua API thin and stable, then adds multi-node capability in shield_cluster.

References ​

Apache License 2.0