> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arupa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 消息

> 在正在运行的服务之间发送同步的点对点消息。

消息机制为运行在同一个内核中的服务提供同步的点对点通信。发送方服务指定一个目标服务，发送一个主题（topic）和一段字节负载，然后等待目标服务返回一个回复。

当一个服务需要另一个服务执行某项操作或返回数据时，请使用消息机制。当数据应该作为状态共享、而不是作为一次请求投递时，请改用 [KV 存储](./isc-kv)。

## 消息信封

该消息就是[协议](./protocol)中描述的 `ServiceMessage`：

| 字段        | 含义                |
| --------- | ----------------- |
| `source`  | 发送方服务的名称，由内核设置该值。 |
| `target`  | 必须接收该消息的服务名称。     |
| `topic`   | 由应用定义的操作或消息类型。    |
| `payload` | 由应用定义的请求数据。       |

目标服务会收到一个 `ServiceMessageReply`：

| 字段        | 含义                          |
| --------- | --------------------------- |
| `error`   | 由目标服务报告的错误。非空值会使这次发送被判定为失败。 |
| `message` | 由应用定义的响应文本或序列化结果。           |

内核不会解释 `topic`、`payload` 或 `message` 的内容，它们的格式由参与通信的服务之间自行定义。您可以使用 JSON、某种生成的消息类型、文本，或其他编码方式，但发送方和目标方必须就此达成一致。

## 发送一条消息

要发送一条消息：

1. 选择目标服务已注册的名称；
2. 选择一个稳定的主题名称；
3. 将请求编码进 `payload`；以及
4. 通过您所用运行时对应的生成的 host 绑定发送该信封。

发送方会一直等待，直到内核把该消息分派给目标服务的消息处理程序。成功的回复中包含目标服务的 `message` 值。发送方服务无法自行选择或覆盖自己的身份；内核会将 source 字段替换为调用方经过身份验证的名称。

## 接收一条消息

目标服务收到的是同一个信封，其中包含由内核提供的 `source`。它应当：

1. 验证该来源服务是否被允许请求该操作；
2. 根据 `topic` 对消息进行路由；
3. 解码并校验 `payload`；以及
4. 返回一个结果或一个错误。

内核不在服务内部提供主题订阅或自动分派机制。目标服务的消息处理程序会接收发给该服务的消息，并负责解释其中的主题。只有 `wasm` 和 `grpc` 服务可以以这种方式接收消息——`static` 服务没有可供分派的处理程序。

## 错误与投递

消息只会被投递给当前正在运行的目标服务。以下情况会导致发送失败：

* `target` 为空；
* 目标服务未在运行；
* 目标处理程序返回了传输或执行错误；或者
* 目标的回复中包含非空的 `error` 字段。

目标返回的 `error` 值会作为错误返回给发送方。当目标不可用时，消息不会被投递给另一个服务。

消息不会被排队、重试、广播或持久化，没有持久化投递保证。如果目标在消息处理过程中停止，调用上下文会随着目标服务的生命周期一起被取消。

## 后端行为

两种服务运行时的消息语义是完全相同的：

* WASM 服务通过生成的 host 绑定发送；以及
* gRPC 服务通过内核的 host 回调通道发送。

内核随后会通过目标服务所用的运行时调用该服务，并将目标的回复转换回发送方对应运行时的响应类型。

## 身份与授权

内核会在 host 边界处对来源服务进行身份验证。服务无法通过在发送请求中写入不同的 `source` 值来冒充另一个服务。

内核层面不存在针对单个主题的访问策略。任何正在运行的服务都可以按名称寻址另一个正在运行的服务，因此当某个主题或负载代表一项特权操作时，目标必须在自己的处理程序中强制执行授权检查。请将 `topic` 视为路由信息，而不是一种访问控制机制。

## 设计一份消息契约

请让消息契约保持明确、且可版本化：

```text theme={null}
target:  secret-manager
topic:   secret.get
payload: {"name":"database"}
reply:   {"value":"..."}
```

请为每个主题编写文档，说明负载的 schema、必需字段、响应格式以及错误含义。在使用之前校验不受信任的负载，并针对未知或格式错误的主题返回明确的错误。

请使用稳定的目标名称和主题命名空间。如果某个请求可以被安全地重复执行，请将该操作设计为幂等的，因为发送方在目标出现临时故障后，可能需要在应用层重试该请求。
