Skip to content

feat: add python client skeleton - #1803

Merged
Nexisato merged 9 commits into
feat/gateway-starterfrom
feat/core/python-rpc-client
Oct 28, 2026
Merged

Nexisato merged 9 commits into
feat/gateway-starterfrom
feat/core/python-rpc-client

Conversation

@Nexisato

@Nexisato Nexisato commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

概述

Python SDK 侧调用 swanlab-core(Go)的客户端骨架:拉起进程、发现端点、建立 gRPC 通道,完成握手与生命周期 RPC,并以 CoreGo 实现 CoreProtocol。依赖 #1776。

代码结构

swanlab/sdk/
├── internal/core_go/
│   ├── __init__.py             # 导出 CoreGo / CoreGoError / ReasonCode
│   ├── config.py               # 超时、端口文件与清理常量
│   ├── errors.py               # Stage、ReasonCode、CoreGoError、reason_for_grpc
│   ├── discovery/__init__.py   # port-file v1 解析、pid 与 UDS 归属校验
│   ├── process/__init__.py     # runtime 目录、spawn、wait → terminate → kill 回收
│   ├── rpc/__init__.py         # Channel:延迟 import grpc,UDS / TCP 回退
│   ├── rpc/core_service.py     # CoreServiceRpc:handshake 与生命周期 RPC
│   ├── launcher.py             # CoreLauncher:start / close / abort
│   └── core.py                 # CoreGo:状态机、session 绑定、fork
├── protocol/core.py            # 新增 NullCoreProtocol(no-op 实现)
└── typings/core_go/__init__.py # RpcChannelType

tests/unit/sdk/internal/core_go/
├── test_errors.py
├── test_launcher.py
├── discovery/                  # test_port_file.py、test_ownership.py
├── process/                    # test_runtime.py、test_spawn.py、test_reap.py
└── rpc/                        # test_channel.py、test_core_service.py

启动与关闭

CoreGo.deliver_run_start()
  → CoreLauncher.start()
      → acquire_runtime()        # 0700 私有目录
      → spawn core               # --port-filename / --parent-pid
      → wait_endpoint()          # 轮询 port-file + 子进程存活校验
      → Channel.open()
  → SpinupService
  → DeliverRunStart
  → session_id 绑定             # RUNNING

CoreGo.close() / abort()
  → TeardownService(尽力)
  → Channel.close()
  → reap_process()               # wait 10s → terminate 3s → kill 2s
  → cleanup_runtime()

行为要点

  • 状态机:NEW → STARTING → RUNNING → FINISHED → CLOSED,启动失败走 ABORTING;close() / abort() 幂等。
  • 会话:一个 CoreGo 绑定一个 session_id,所有 run 级 RPC 显式携带;多 run 由多个 CoreGo 表达。
  • 未实现的数据面:Go 侧 upsert_* 返回 UNIMPLEMENTED,客户端记录一次 warning 后不重试、不改写、不回退 CorePython。
  • 模式:CoreGo 当前只实现 online;local / offline 返回 MODE_UNSUPPORTED,disabled 为 no-op。CoreProtocol 与 CorePython 的四种模式不变。
  • fork:core.fork() 返回 _DetachedCoreGo(继承 NullCoreProtocol),不持有父进程的 launcher / channel / session,调用返回 FORK_UNSUPPORTED,不影响父 Core;仅覆盖显式 os.fork(),macOS 默认 spawn 需在子进程重新 swanlab.init()。

边界

  • create_core() 未改动,生产路径仍走 CorePython;CoreEnum.CORE → CoreGo 的切换在后续切片。
  • 共享 launcher 的 attach 模式、数据面 RPC、detached 运行均不在本轮。

测试

  • tests/unit/sdk/internal/core_go/ 覆盖发现、进程、RPC、launcher 与错误映射,109 passed。
  • 全量 pytest tests/unit:2138 passed / 21 skipped;basedpyright 0 errors;ruff check / ruff format --check 通过。
  • 真实二进制 smoke 本地执行、不入库:UDS happy path、TCP 回退、abort 幂等、binary 缺失、UNIMPLEMENTED、重复 close。

合并顺序

1803 → 1776 (feat/gateway-starter) → feature/core

- add fixed handshake constants shared by client modules
- add CoreGoError with stage/reason and gRPC status-name mapping
- parse port-file v1 with Go portinfo parity
- validate pid and unix/tcp endpoint ownership
- create private 0700 runtime dirs under the system temp root
- spawn swanlab-core with port-file/parent-pid only and sanitized env
- poll endpoint, classify early exit codes and validate ownership
- reap with wait -> terminate -> kill and keep bounded stderr
- lazily import grpcio and wait for channel readiness
- map gRPC statuses once and preserve UNIMPLEMENTED details
- attach session_id to every run-level request
- convert success=false responses into protocol errors
- add RpcChannelType Protocol under swanlab.sdk.typings.core_go
- switch core_go modules to absolute imports and drop the rpc re-export
- report missing grpcio as GRPC_UNAVAILABLE instead of leaking ImportError
- skip POSIX mode/uid checks on Windows runtime dirs
- add CoreLauncher as the sole owner of runtime, process and channel
- validate binary before creating runtime and clean up on any start failure
- make close/abort idempotent and guard fork children via pkg.fork
- reuse validate_core_binary and cover launcher orchestration with unit tests
@Nexisato Nexisato added 💪 enhancement New feature or request 🆕 version SwanLab new version labels Oct 27, 2026
- add CoreGo state machine and single session_id binding
- start via launcher, SpinupService and DeliverRunStart
- forward upserts and surface UNIMPLEMENTED once without fallback
- map finish/stats/confirm and keep close/abort idempotent
- return a NullCoreProtocol-based detached stub for fork children
@Nexisato
Nexisato marked this pull request as ready for review October 28, 2026 02:42
Resolve core binary paths before launching from the runtime directory, and use safe.block to contain cleanup failures during teardown and channel close. Add a regression test for relative binary paths.
@Nexisato
Nexisato merged commit 8726713 into feat/gateway-starter Oct 28, 2026
20 checks passed
@Nexisato
Nexisato deleted the feat/core/python-rpc-client branch October 28, 2026 05:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💪 enhancement New feature or request 🆕 version SwanLab new version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant