Procedures: CallProcedure + ProcedureResult #11

Closed
opened 2026-08-19 06:49:40 +00:00 by yuris · 1 comment
Owner

Wire the procedure path symmetric to reducers. Handlers stubbed in connection.lua; needs tests and a live-module verification.

  • call_procedure API
  • ProcedureResult decode: Returned vs InternalError
  • Test with a module that has a procedure
Wire the procedure path symmetric to reducers. Handlers stubbed in connection.lua; needs tests and a live-module verification. - [ ] call_procedure API - [ ] ProcedureResult decode: Returned vs InternalError - [ ] Test with a module that has a procedure
Author
Owner

Closed in a20f026

db:call_procedure("echo", { "from defold" }, function(err, value)
  print(value)   -- echo: from defold
end)

A ProcedureResult handler already existed, but nothing could reach it — there was no send path — and it handed back the raw message. A procedure differs from a reducer in the one way that matters to a client: it returns a value.

Verified against a real module

Added three procedures to the test module (u64 return, string return with args, one that throws), published, and captured the traffic. Four new fixture frames.

1. The return value is double-encoded — the same ByteString rule that bit reducer args in #4:

procedure status.Returned decoded
count_messages → u64 "2" 2
echo("from lua") → string "\"echo: from lua\"" echo: from lua

protocol.decode_payload unwraps it, so the callback gets a real Lua value.

2. Every failure is InternalError. A procedure that throws and a name that does not exist produce the same status, differing only in message:

{"InternalError":"The module instance encountered a fatal error: Uncaught Error: procedure failed on purpose ..."}
{"InternalError":"No such procedure"}

So there is no "no such procedure" variant to branch on. Failed is in the schema but was never observed; it is handled anyway.

3. request_id correlates directly, not Option-wrapped like SubscriptionError's.

Generator limitation found on the way

The HTTP schema endpoint has no procedures key at all (2.8.2), though spacetime describe --json lists them fine. So tools/gen-schema.sh cannot emit procedure names — noted in the script header. Call them by canonical snake_case, same rule as reducers (countMessages → count_messages).

Proof

Conformance runs a fourth phase in a real Defold engine, covering both the success and failure paths:

SMOKE: PHASE3 OK unsubscribed query set 1; cache drained
SMOKE: procedure returned "echo: from defold"
SMOKE: PASS procedure round trip; failure surfaced as an error
## Closed in a20f026 ```lua db:call_procedure("echo", { "from defold" }, function(err, value) print(value) -- echo: from defold end) ``` A `ProcedureResult` handler already existed, but nothing could reach it — there was no send path — and it handed back the raw message. A procedure differs from a reducer in the one way that matters to a client: **it returns a value**. ## Verified against a real module Added three procedures to the test module (u64 return, string return with args, one that throws), published, and captured the traffic. Four new fixture frames. **1. The return value is double-encoded** — the same ByteString rule that bit reducer args in #4: | procedure | `status.Returned` | decoded | |---|---|---| | `count_messages` → u64 | `"2"` | `2` | | `echo("from lua")` → string | `"\"echo: from lua\""` | `echo: from lua` | `protocol.decode_payload` unwraps it, so the callback gets a real Lua value. **2. Every failure is `InternalError`.** A procedure that throws and a name that does not exist produce the *same* status, differing only in message: ``` {"InternalError":"The module instance encountered a fatal error: Uncaught Error: procedure failed on purpose ..."} {"InternalError":"No such procedure"} ``` So there is no "no such procedure" variant to branch on. `Failed` is in the schema but was never observed; it is handled anyway. **3. `request_id` correlates directly**, not Option-wrapped like `SubscriptionError`'s. ## Generator limitation found on the way The HTTP schema endpoint has **no `procedures` key at all** (2.8.2), though `spacetime describe --json` lists them fine. So `tools/gen-schema.sh` cannot emit procedure names — noted in the script header. Call them by canonical snake_case, same rule as reducers (`countMessages` → `count_messages`). ## Proof Conformance runs a fourth phase in a real Defold engine, covering both the success and failure paths: ``` SMOKE: PHASE3 OK unsubscribed query set 1; cache drained SMOKE: procedure returned "echo: from defold" SMOKE: PASS procedure round trip; failure surfaced as an error ```
yuris closed this issue 2026-08-19 09:52:10 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
yuris/spacetimedb-defold#11
No description provided.