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

# 快速开始

> 在本机跑通第一个 BlockX task：启动 worker、提交 task、看懂结果

这一页是一条不分叉的最短路径：从克隆仓库到看见第一个 task 的返回值，全程不依赖 etcd、BlockDB、Meta 或链节点。跑完之后你会对照架构文档知道刚才发生了什么。

想先建立整体印象，看 [架构总览](/architecture/overview)；需要完整的依赖表、Makefile 目标和环境变量清单，看 [本地开发环境](/development/getting-started)。

## 前置

* Go（`go.mod` 声明 `go 1.26.4`）和可用的 C 编译器 —— `cmd/worker` 链接 DuckDB，必须开 CGO
* Python ≥ 3.12 与 [`uv`](https://docs.astral.sh/uv/)
* 能通过 git 访问 `github.com/Chaintable/*` 私有仓库（Go 与 Python 依赖都有私有包）

## 五步跑通

<Steps>
  <Step title="克隆并装依赖">
    ```bash theme={null}
    git clone git@github.com:Chaintable/blockx.git
    cd blockx
    go mod download
    uv sync --project python
    ```

    第二条命令在 `python/.venv/` 建出 executor 用的 venv，下一步的 `PYTHON_BIN` 要指向它。
  </Step>

  <Step title="编译 worker">
    ```bash theme={null}
    go build -o /tmp/blockx-worker ./cmd/worker
    ```

    首次编译要链接 DuckDB 静态库，比其他包慢；之后走构建缓存。
  </Step>

  <Step title="启动 worker">
    ```bash theme={null}
    WORKER_LISTEN=127.0.0.1:9221 \
    WORKER_ADDR=127.0.0.1:9221 \
    EXECUTOR_COUNT=1 \
    PYTHON_BIN=$PWD/python/.venv/bin/python \
    PYTHONPATH=$PWD/python \
    ETCD_ENDPOINTS=none \
    ICEBERG_NAMESPACE=chaintable_test \
    BLOCKX_USAGE_DISABLED=true \
    BLOCKDB_BATCH_WRITE_ADDR=127.0.0.1:1 \
    STUB_BLOCKDB_DELAY_MS=0 \
    /tmp/blockx-worker
    ```

    日志出现 `worker listening` 和 `executor started` 就绪。这十项都是必需的：少了 `ICEBERG_NAMESPACE` 或 `BLOCKDB_BATCH_WRITE_ADDR`，进程在配置校验阶段直接退出（`WorkerFullConfig.Validate` 与 `validateProfileRuntimeConfig`）。`ETCD_ENDPOINTS=none` 表示不注册到 etcd，也就没有 Coordinator 参与；`BLOCKDB_BATCH_WRITE_ADDR` 填一个不可达端口即可，`STUB_BLOCKDB_DELAY_MS=0` 把读路径切回 devstub。
  </Step>

  <Step title="启动本地 proxy（另开一个终端）">
    ```bash theme={null}
    cd examples/local_test_service
    uv sync
    uv run python local_proxy.py
    ```

    blockx-py 只通过 `PROXY_SOCKET_PATH` 指定的 UDS proxy 连接（线上那一环是 notebook 执行引擎的组件，不随本仓库发布），`local_proxy.py` 在本地补上它：把 `WorkerService` 的四个 RPC 字节级转发给 worker，并把两套 coordinator 的 `ReserveWorkerSlot` 垫成对 worker 自己的 `RequestTaskSlot`。

    输出 `[proxy] listening on unix:/tmp/blockx-proxy.sock -> worker 127.0.0.1:9221` 即就绪。
  </Step>

  <Step title="提交 task">
    ```bash theme={null}
    uv run python submit.py
    ```

    ```
    [{'message': 'hello, ct2'}, {'message': 'hello, blockx'}]
    ```

    结果按各次调用的**完成序**收集，不保证与 `callList` 的行序一致 —— 多次调用在 executor 内并发执行。需要结果与入参的对应关系时，让返回值自己带上入参，本例的 `message` 里就带着 `name`。
  </Step>
</Steps>

## 你刚才提交了什么

`submit.py` 的核心是一段 function code 加一份 call 配置：

```python theme={null}
source_code = """
from blockx import LocalTestService

def _(name):
    return {"message": LocalTestService().helloworld(name)}
"""

task = TaskBuilder.build(
    CallListCallConfig(
        func=Function(source_code=source_code),
        callList=[["ct2"], ["blockx"]],
    ),
    ReturnValueResultHandler(),
)
result = task.submit(timeout=30)
```

三个要点：

* **入口函数名必须是 `_`**，每次调用拿到 `callList` 的一行作为位置参数。两行就是两次调用。
* **`CallListCallConfig` 是 Builder**，决定这个 task 展开成哪些 call；`ReturnValueResultHandler` 是 Plugin，决定结果怎么收口。
* **`LocalTestService` 是 worker 内置的示例能力后端**。function code 里它是个普通 gRPC client，executor 启动时把 channel 换成 BridgeChannel，调用被截回 worker 进程内分派 —— 这就是接入新能力后端的范式，见 [后端适配器](/components/backend-adapter)。

## 结果里能看到什么

worker 的 `task_finished` 日志把这次执行拆成了三个阶段：

```json theme={null}
{"msg":"task finished","state":"SUCCEEDED","task_duration_ms":14,"output_count":2,
 "phases":[{"phase":"builder","status":"success","call_count":2},
           {"phase":"calls","status":"success","call_count":2},
           {"phase":"writer","status":"success","plugin_name":"ReturnValueResultHandler"}],
 "io_backends":[{"backend":"localtestservice",
                 "operation":"/localtestservice.v1.LocalTestService/HelloWorld","ops_success":2}]}
```

`builder → calls → writer` 就是 Worker 的三阶段状态机：Builder 把配置展开成 call 列表，Calls 阶段在 executor 里并发跑 function code，Writer 阶段交给 Plugin 收口。`io_backends` 记录了这次 task 打到的能力后端与调用次数。展开讲在 [Task 生命周期](/architecture/task-lifecycle)。

<Tip>
  不想起 proxy，也可以直接跑一条 process E2E 看真实调用链：
  `go test -v -timeout 300s ./cmd/worker/ -run TestWorkerProcess_RequestSlotAndSubmit`
</Tip>

## 卡住了

| 现象                                                                 | 原因                                                                                                                                |
| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| worker 启动即退出，`invalid worker runtime config`                       | 按错误串补变量：`icebergNamespace must not be empty` 补 `ICEBERG_NAMESPACE`；`requires blockdb.batchWriteAddr` 补 `BLOCKDB_BATCH_WRITE_ADDR` |
| `build constraints exclude all Go files in duckdb-go-bindings/lib` | `CGO_ENABLED=0` 的症状。worker 必须开 CGO 并有 C 编译器                                                                                       |
| executor 反复重启                                                      | `PYTHON_BIN` 没指向 `python/.venv/bin/python`，或漏了在仓库根 `uv sync --project python`                                                     |
| `PROXY_SOCKET_PATH not set` / `UNAVAILABLE`                        | proxy 没起，或 socket 路径与 `submit.py` 不一致（默认都是 `/tmp/blockx-proxy.sock`）                                                              |
| task 失败且 `failure_code` 为 `CALL_FAILED`                            | function code 内部抛异常。若启动时设了 `LOCAL_TEST_SERVICE_DISABLED=true`，worker 日志里会是 `no adapter registered for backend: localtestservice`  |
| `go mod download` 拉不到 `github.com/Chaintable/*`                    | 私有模块。配好 git 凭据并设 `GOPRIVATE=github.com/Chaintable/*`                                                                              |

更多问题见 [本地开发环境](/development/getting-started) 的常见问题一节。

## 下一步

<Columns cols={2}>
  <Card title="架构总览" icon="layers" href="/architecture/overview">
    组件构成、核心约束与建议阅读顺序。
  </Card>

  <Card title="Task 生命周期" icon="route" href="/architecture/task-lifecycle">
    刚才那个 task 在系统里的完整时序。
  </Card>

  <Card title="本地开发环境" icon="terminal" href="/development/getting-started">
    完整依赖表、Makefile 目标与环境变量清单。
  </Card>

  <Card title="贡献流程" icon="git-pull-request" href="/development/contributing">
    改代码之前先读这页。
  </Card>
</Columns>
