> ## 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.

# 用 Go 提交任务

> 通过 gRPC 预留 Worker 槽位、提交任务并观察结果。

使用 BlockX 仓库 `api/grpc/worker/workerpb` 中的 Go 绑定直接接入 Worker。此示例用一个简单函数验证任务传输。EVM 状态读取与 trace 转换见[执行一次计算](/zh/guides/run-once)和[按区块计算](/zh/guides/block-computation)。

## 前置条件

* 完成[快速开始](/zh/quickstart)，并保持本地 Worker 运行。
* 从 BlockX 仓库运行 Go 程序，使用该仓库的 `go.mod` 和生成的绑定。
* 此本地示例通过回环地址使用明文 gRPC。接入远程 Worker 时，使用你的部署所需的传输配置。

## 预留、提交与观察

将以下程序保存为 `/tmp/blockx-grpc-example.go`。它先调用 `RequestTaskSlot`，再提交带 `ReturnValueHandler` 的 `InputsCallConfig`，并持续连接 `WatchTasks`，直到收到终态结果。

```go theme={null}
package main

import (
	"context"
	"flag"
	"fmt"
	"io"
	"log"
	"time"

	"github.com/google/uuid"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	workerpb "github.com/Chaintable/blockx/api/grpc/worker/workerpb"
)

func main() {
	addr := flag.String("worker", "127.0.0.1:9221", "Worker address")
	flag.Parse()
	conn, err := grpc.NewClient("passthrough:///"+*addr,
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	client := workerpb.NewWorkerServiceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()

	taskID := uuid.NewString()
	fmt.Println("task:", taskID)
	slot, err := client.RequestTaskSlot(ctx, &workerpb.RequestTaskSlotRequest{
		TaskId: taskID, TtlMs: 5000,
	})
	if err != nil {
		log.Fatal(err)
	}
	submit, err := client.SubmitTask(ctx, &workerpb.SubmitTaskRequest{
		SlotId: slot.GetSlotId(),
		Task: &workerpb.TaskInput{
			TaskId: taskID,
			FunctionCallConfig: &workerpb.FunctionCallConfig{
				Type:   "InputsCallConfig",
				Config: []byte(`{"function":"","code":{"sourceCode":"def _(name):\n    return {\"message\": f\"hello, {name}\"}\n"},"callList":[["ct2"],["blockx"]]}`),
			},
			ResultHandler: &workerpb.ResultHandler{Type: "ReturnValueHandler", Config: []byte(`{}`)},
			TaskTimeoutMs: 30000,
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("submitted:", submit.GetState())

	stream, err := client.WatchTasks(ctx, &workerpb.WatchTasksRequest{TaskIds: []string{taskID}})
	if err != nil {
		log.Fatal(err)
	}
	for {
		update, err := stream.Recv()
		if err == io.EOF {
			log.Fatal("watch ended before a terminal result; inspect task ", taskID)
		}
		if err != nil {
			log.Fatal(err)
		}
		if update.GetError() != "" {
			log.Fatal(update.GetError())
		}
		if !update.GetIsTerminal() {
			continue
		}
		result := update.GetResult()
		if result == nil {
			log.Fatal("terminal update has no result")
		}
		fmt.Println("state:", update.GetState())
		if !result.GetSuccess() {
			log.Fatalf("task failed: %s: %s", result.GetExecuteResult().GetFailureCode(),
				result.GetExecuteResult().GetFailureMessage())
		}
		for _, p := range result.GetExecuteResult().GetPluginResults() {
			fmt.Printf("%s success=%v result=%s\n", p.GetPluginName(), p.GetSuccess(), p.GetResult())
		}
		return
	}
}
```

在 BlockX 仓库运行：

```bash theme={null}
go run /tmp/blockx-grpc-example.go -worker 127.0.0.1:9221
```

输出包含任务 ID、终态和两条问候结果，结果顺序可能不同。如果任务失败、Worker 返回任务未知，或流在终态结果到达前结束，程序会报错退出。

## 接入调度与结果查询

* 使用 Coordinator 分配资源时，先调用 `CoordinatorService.ReserveWorkerSlot`。连接返回的 `worker_addr`，并将 `slot_id` 传给 `SubmitTask`。
* 任务执行期间保持 Watch 流连接。断连行为见[执行语义](/zh/concepts/execution-semantics)。
* 连接失败时，保留已打印的任务 ID。先查询该任务，再决定是否提交新工作。
* 请求中的 `config` 字节包含所选 Call Builder 或 Writer Plugin 的 JSON。将其替换为你的 EVM 计算配置。

## 继续阅读

* [服务 API](/zh/reference/service-api)
* [任务配置](/zh/reference/task-configuration)
* [查询结果与处理失败](/zh/guides/results-and-failures)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.