3 Commits
Author SHA1 Message Date
zeekayandHanzo Dev 679ae61163 feat(transport): address the engine and the SDK, so both can use a socket
The engine took a PORT and the SDK an Options.HostPort, so neither end
could use a unix socket for traffic that never leaves the host. The
field name was not the only obstacle: luxfi/zap bound net.Listen("tcp",
":port") and reached a peer with net.DialTimeout("tcp", addr), so a path
was refused at the dialer with "missing port in address" and could not
be bound at all. That is fixed upstream (luxfi/zap Address + Network);
this pins the commit until it is tagged.

EmbedConfig.Address, Embedded.Address, ServeGated(addr) and
client.Options.Address each take ONE address, because a port is a detail
of one transport rather than a thing every listener has. A path binds or
dials a unix socket; anything else is host:port.

TestDialRequiresHostPort became TestDialRequiresAddress: Dial needs an
address, and asserts a socket path is refused for being absent rather
than for being portless. TestE2E_UnixSocket runs a real workflow over a
socket end to end, and TestE2E_UnixSocketRebind proves the socket is
unlinked on stop so a restart binds cleanly.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 16:27:19 -07:00
zeekay 5e5e525d5f feat(sdk/examples): add Embed + Realtime samples (6/6 ZAP-only tests)
pkg/sdk/examples/embed.go — boots tasks.Embed in-process on an
ephemeral port, dials it via pkg/sdk/client, round-trips Health →
ExecuteWorkflow → ListWorkflows. This is the canonical "single
binary" pattern Hanzo Base apps use when TASKS_EMBED=true.

pkg/sdk/examples/realtime.go — exercises the full realtime pipeline:
embedded daemon → engine broker → SSE handler → client.SubscribeEvents
→ caller channel. Starts 3 workflows, cancels even-indexed, asserts
events arrived on the SDK channel. Proves the realtime path works
end-to-end without HTTP proxy or gRPC.

Tests:
  TestHealth      PASS
  TestHello       PASS
  TestSignal      PASS
  TestCron        PASS
  TestEmbed       PASS  (NEW — Base TASKS_EMBED path)
  TestRealtime    PASS  (NEW — SSE → SDK channel pipeline)

All over native ZAP. Zero gRPC. Zero go.temporal.io. Zero proxy.
2026-04-27 00:13:34 -07:00
zeekay 38e44b507d feat(sdk/examples): ZAP-only integration tests + engine wire fixes
pkg/sdk/examples/{hello,signal,cron}.go drive the engine end-to-end
through pkg/sdk/client over the ZAP wire — zero HTTP, zero
go.temporal.io. Tests boot tasks.Embed in-process, dial the local
ZAP node, and round-trip every workflow + schedule opcode.

Engine fixes (pkg/tasks/embed.go):
- ZAP handlers now read the SDK's snake_case JSON shape
  (workflow_id / workflow_type / task_queue / signal_name / schedule_id)
  in addition to the camelCase shape used by the HTTP shim
- DescribeWorkflow returns {info: WorkflowExecutionInfo} (SDK shape)
- WorkflowExecutionInfo emits status as int8 (1=RUNNING / 4=CANCELED / 5=TERMINATED)
- StartWorkflow returns {run_id, workflow_id}
- PauseSchedule respects the requested paused flag (was always true)
- Schedule list response goes through scheduleSDK marshaller
- Empty time.Time fields are omitted (SDK can't parse "")

Store fix:
- store.list() snapshots under RLock then iterates without lock,
  preventing the RWMutex upgrade deadlock that hung GET /v1/tasks/...
  whenever the cron sweeper's put() was waiting on a Lock that
  competed with reader RLocks

go test ./pkg/sdk/examples/... → 4/4 PASS:
  TestHealth, TestHello, TestSignal, TestCron
2026-04-26 22:37:53 -07:00