Skip to content

Commit a12fcb7

Browse files
committed
docs(moonzero): correct four claims that were not true of the code.
AGENTS.md listed a `retry.mbt` that does not exist — there is no retry primitive here at all — and said `discov/` implements `ConsulHttp` and `RedisConn`. It does not: those traits' only implementations are the test fakes, because the traits are synchronous and the sockets are async, so `ConsulClient` and `RedisClient` cannot reach a real server today. It also claimed `discov/` tracks a generated interface; `moon info` skips native-only packages, so it does not. The README and `registry.mbt` said the balancer honours an endpoint's weight. Neither the round-robin nor the pick-first balancer reads it — it is carried for a weighted balancer that does not exist yet. `etcd_discovery.mbt` told the reader to renew a lease with "the client's keep-alive". There is no keep-alive method on either client, so every etcd registration silently lapses at its TTL. Signed-off-by: Leo Cheng (heke1228) <chengkelfan@qq.com>
1 parent 0c5b4e3 commit a12fcb7

3 files changed

Lines changed: 8 additions & 5 deletions

File tree

AGENTS.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
- `moon fmt` before anything else. CI runs `moon fmt && git diff --exit-code`, so an unformatted file fails the build on its own.
66
- `moon check --target all --deny-warn` is the gate. Warnings are errors, and all four backends (wasm, wasm-gc, js, native) must pass. Run it again after the first round of fixes: a package whose sources do not compile hides the diagnostics in its own test files, so errors surface in waves.
77
- `moon test --target all` at the root; `moon test --target native` inside `discov/`.
8-
- `moon info` regenerates `pkg.generated.mbti`. If that file does not change, your edit is not visible to anyone depending on this package, which usually means the refactor was safe. If it does change, read the diff before committing — that is the public interface moving. The examples regenerate their own, which is why those are gitignored.
8+
- `moon info` regenerates `pkg.generated.mbti`. If that file does not change, your edit is not visible to anyone depending on this package, which usually means the refactor was safe. If it does change, read the diff before committing — that is the public interface moving. `moon info` skips a package pinned to `supported_targets = "native"`, so `discov/` has no tracked interface and its drift is invisible to review. The examples regenerate their own, which is why those are gitignored.
99
- CI installs the latest moon on every run, so a toolchain that is behind will disagree with it. Upgrade locally rather than pinning.
1010

1111
# Layout
1212

13-
Root is portable and has no async dependency: `config.mbt`, `yaml.mbt`, the resilience middleware (`breaker.mbt`, `maxconns.mbt`, `limits.mbt`, `retry.mbt`), `metrics.mbt`, `tracing.mbt`, `jwt.mbt`, `discovery.mbt`, and the zrpc client. `discov/` is `supported_targets = "native"` and carries the drivers that speak to real etcd, consul and redis over sockets, plus the file-backed registry. Tests sit beside their subject as `*_wbtest.mbt` at the root and `*_test.mbt` under `discov/`; `examples/NN-topic/` are runnable one-file demos.
13+
Root is portable and has no async dependency: `config.mbt`, `yaml.mbt`, the resilience middleware (`breaker.mbt`, `maxconns.mbt`, `limits.mbt`, `periodlimit.mbt`, `ratelimit.mbt`), `metrics.mbt`, `tracing.mbt`, `jwt.mbt`, `discovery.mbt`, and the zrpc client. `discov/` is `supported_targets = "native"` and carries the drivers that speak to real etcd, consul and redis over sockets, plus the file-backed registry. Tests sit beside their subject as `*_wbtest.mbt` at the root and `*_test.mbt` under `discov/`; `examples/NN-topic/` are runnable one-file demos.
1414

1515
# Things worth knowing
1616

1717
- Middleware is async — `Middleware` is `(async App) -> async App` — but the root package deliberately does not depend on `moonbitlang/async`, so it cannot host an `async test`. End-to-end middleware tests belong in `discov/`, which already imports async and runs native-only. `maxconns_release_test.mbt` is the pattern to copy.
1818
- Anything holding a resource across a call into user code must release it with `defer`, not with a trailing statement or a `catch` that re-raises. Both skip cancellation, and the compiler's `fragile_catch_all` lint now says so. `max_conns` leaked a permit exactly this way and wedged the limiter shut at 503.
1919
- The tests against real etcd, consul and redis are gated on `MOON_ETCD_TEST`, `MOON_CONSUL_TEST` and `MOON_REDIS_TEST`; without them the suite silently skips those. CI sets them and starts the containers.
20-
- `ConsulHttp` and `RedisConn` are `pub trait`, which in MoonBit is sealed — only this package can implement them. Consumers therefore cannot build a `ConsulClient` or `RedisClient` of their own; the transports in `discov/` are the only implementations.
20+
- `ConsulHttp` and `RedisConn` are `pub trait`, which in MoonBit is sealed — only this package can implement them, and right now the only implementations are the test fakes. `discov/`'s `ConsulSocket` and `RedisSocket` are real network clients but do not implement those traits, because the traits are synchronous and the sockets are not. So `ConsulClient`, `RedisClient`, `ConsulDiscovery` and `RedisDiscovery` cannot reach a real server today; closing that means making the traits async and implementing them in `discov/`, or moving the clients there.
21+
- The resilience primitives are not ports of go-zero's algorithms and their doc comments say so: the breaker is a consecutive-failure state machine rather than go-zero's probabilistic rolling-window `googleBreaker`, and both limiters are process-local rather than Redis-Lua-backed, so N replicas admit N times the quota.

docs/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@
232232
<div class="item" data-k="fn"><span class="kind">fn</span><pre class="sig"><span class="k">fn</span> <span class="ty">RpcServer</span>::dispatch_graceful( self : <span class="ty">RpcServer</span>, coord : <span class="ty">ShutdownCoordinator</span>, path : <span class="ty">String</span>, request : <span class="ty">Bytes</span>) <span class="op">-&gt;</span> <span class="ty">Result</span>[<span class="ty">Bytes</span>, @moonrpc.<span class="ty">Status</span>]</pre><p class="doc">Dispatch a unary call through the shutdown gate: refuse with <code>Unavailable</code> when the server is shutting down, otherwise run the handler and count it as in-flight for the duration so a concurrent shutdown drains behind it. The gate wraps <code>RpcServer::dispatch</code>, so an unregistered path still yields <code>Unimplemented</code>.</p></div>
233233
</section>
234234
<section class="pkg" id="registry"><h2><span class="at">§</span>Service registry & discovery</h2><p class="pdesc">An InMemoryRegistry (etcd-shaped: service -&gt; instance -&gt; endpoint with a store revision) plus RoundRobin/pick_first balancers and resolve_one, the resolve-then-balance step a client runs before a call.</p>
235-
<div class="item" data-k="struct"><span class="kind">struct</span><pre class="sig"><span class="k">struct</span> <span class="ty">Endpoint</span></pre><p class="doc">A service endpoint (← go-zero&#x27;s <code>discov</code> target): the host and port an instance listens on, plus a routing weight the balancer honours (default <code>1</code>).</p></div>
235+
<div class="item" data-k="struct"><span class="kind">struct</span><pre class="sig"><span class="k">struct</span> <span class="ty">Endpoint</span></pre><p class="doc">A service endpoint (← go-zero&#x27;s <code>discov</code> target): the host and port an instance listens on, plus a routing weight (default <code>1</code>). It is carried through registration and snapshots for a weighted balancer; the balancers shipping today — round-robin and pick-first — do not read it yet.</p></div>
236236
<div class="item" data-k="fn"><span class="kind">fn</span><pre class="sig"><span class="k">fn</span> <span class="ty">Endpoint</span>::new(host : <span class="ty">String</span>, port : <span class="ty">Int</span>, weight<span class="op">?</span> : <span class="ty">Int</span> = 1) <span class="op">-&gt;</span> <span class="ty">Endpoint</span></pre><p class="doc">Build an endpoint; <code>weight</code> defaults to <code>1</code>, matching an unweighted instance.</p></div>
237237
<div class="item" data-k="fn"><span class="kind">fn</span><pre class="sig"><span class="k">fn</span> <span class="ty">Endpoint</span>::address(self : <span class="ty">Endpoint</span>) <span class="op">-&gt;</span> <span class="ty">String</span></pre><p class="doc">The <code>host:port</code> dial string.</p></div>
238238
<div class="item" data-k="struct"><span class="kind">struct</span><pre class="sig"><span class="k">struct</span> <span class="ty">InMemoryRegistry</span></pre><p class="doc">An in-memory service registry (← go-zero&#x27;s etcd <code>discov</code> store, minus the network): a two-level map of <code>service -&gt; instance-id -&gt; endpoint</code> and a monotonic revision bumped on every mutation, mirroring etcd&#x27;s store revision so a watcher could detect change. Instance ids are <code>&lt;service&gt;/&lt;n&gt;</code>, the leaf of the etcd key an instance would lease.</p></div>

registry.mbt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
///|
22
/// A service endpoint (← go-zero's `discov` target): the host and port an
3-
/// instance listens on, plus a routing weight the balancer honours (default `1`).
3+
/// instance listens on, plus a routing weight (default `1`). It is carried through registration and
4+
/// snapshots for a weighted balancer; the balancers shipping today — round-robin and
5+
/// pick-first — do not read it yet.
46
pub(all) struct Endpoint {
57
host : String
68
port : Int

0 commit comments

Comments
 (0)