This is an automated email from the ASF dual-hosted git repository.

xuetaoli pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go-samples.git


The following commit(s) were added to refs/heads/main by this push:
     new 8af31d88 feat: samples for k8s probe (#1033)
8af31d88 is described below

commit 8af31d88afd2bffc9b31ec9d5af67936d44cd04a
Author: Xuetao Li <[email protected]>
AuthorDate: Mon Mar 16 16:40:24 2026 +0800

    feat: samples for k8s probe (#1033)
    
    * feat: samples for k8s probe
    
    * import format
    
    * add integrate test for probe
    
    * fix comment
---
 README.md                                          |   4 +-
 README_CN.md                                       |   4 +-
 metrics/probe/README.md                            | 166 +++++++++++++++++++
 metrics/probe/README_CN.md                         | 177 +++++++++++++++++++++
 metrics/probe/deploy/server-deployment.yml         |  43 +++++
 metrics/probe/go-client/cmd/main.go                | 161 +++++++++++++++++++
 metrics/probe/go-server/Dockerfile                 |   6 +
 metrics/{ => probe}/go-server/build.sh             |  21 ++-
 metrics/probe/go-server/cmd/main.go                | 142 +++++++++++++++++
 metrics/{ => prometheus_grafana}/Deployment.yml    |   0
 metrics/{ => prometheus_grafana}/README.md         |   4 +-
 metrics/{ => prometheus_grafana}/README_CN.md      |   4 +-
 .../{ => prometheus_grafana}/assert/grafana.png    | Bin
 .../{ => prometheus_grafana}/docker-compose.yml    |   0
 .../{ => prometheus_grafana}/go-client/Dockerfile  |   0
 .../{ => prometheus_grafana}/go-client/build.sh    |   0
 .../{ => prometheus_grafana}/go-client/cmd/main.go |   0
 .../{ => prometheus_grafana}/go-server/Dockerfile  |   0
 .../{ => prometheus_grafana}/go-server/build.sh    |   0
 .../{ => prometheus_grafana}/go-server/cmd/main.go |   0
 metrics/{ => prometheus_grafana}/grafana.json      |   0
 .../{ => prometheus_grafana}/prometheus_pull.yml   |   0
 .../{ => prometheus_grafana}/prometheus_push.yml   |   0
 metrics/{ => prometheus_grafana}/proto/greet.pb.go |   2 +-
 metrics/{ => prometheus_grafana}/proto/greet.proto |   2 +-
 .../{ => prometheus_grafana}/proto/greet.triple.go |   0
 start_integrate_test.sh                            |   3 +
 27 files changed, 727 insertions(+), 12 deletions(-)

diff --git a/README.md b/README.md
index 88903866..94fd2f16 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,9 @@ Please refer to [HOWTO.md](HOWTO.md) for detailed 
instructions on running the sa
   * `service_discovery/service`: Java/Go interoperability with Nacos using 
application-level service discovery (Dubbo3 model).
 * `llm`: Example of integrating Large Language Models (LLMs) with Dubbo-go.
 * `logger`: Logging examples for Dubbo-go applications.
-* `metrics`: Shows how to collect and expose metrics from Dubbo-go services, 
supporting both Prometheus Push and Pull modes. Also includes the `pgw-cleaner` 
tool for cleaning zombie metrics in Push mode.
+* `metrics`: Observability-related samples.
+  * `metrics/prometheus_grafana`: Shows how to collect and expose metrics from 
Dubbo-go services, supporting both Prometheus Push and Pull modes. Also 
includes the `pgw-cleaner` tool for cleaning zombie metrics in Push mode.
+  * `metrics/probe`: Demonstrates Dubbo-go Kubernetes probe endpoints 
(`/live`, `/ready`, `/startup`) and deployment usage.
 * `mesh`: Proxy-based service mesh example showing how to deploy Dubbo-go 
services with Envoy on Kubernetes.
 * `online_boutique`: Microservices “online boutique” demo built with Dubbo-go.
 * `otel/tracing`: Distributed tracing examples using OpenTelemetry.
diff --git a/README_CN.md b/README_CN.md
index 1c0940a1..f6250068 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -36,7 +36,9 @@
   * `service_discovery/service`:基于 Nacos 的应用级服务发现(Dubbo3 模型)Java/Go 互操作示例。
 * `llm`:将大模型(LLM)集成到 Dubbo-go 中的示例。
 * `logger`:Dubbo-go 应用的日志使用示例。
-* `metrics`:展示如何采集并暴露 Dubbo-go 服务的指标,支持 Prometheus Push 和 Pull 两种模式;同时包含用于清理 
Push 模式僵尸指标的 `pgw-cleaner` 工具。
+* `metrics`:可观测性相关示例。
+  * `metrics/prometheus_grafana`:展示如何采集并暴露 Dubbo-go 服务指标,支持 Prometheus Push 和 
Pull 两种模式;同时包含用于清理 Push 模式僵尸指标的 `pgw-cleaner` 工具。
+  * `metrics/probe`:演示 Dubbo-go 在 Kubernetes 
场景下的探针端点(`/live`、`/ready`、`/startup`)及部署方式。
 * `mesh`:基于代理的服务网格示例,展示如何在 Kubernetes 上结合 Envoy 部署 Dubbo-go 服务。
 * `online_boutique`:基于 Dubbo-go 构建的微服务 “在线商城” 演示项目。
 * `otel/tracing`:使用 OpenTelemetry 的分布式链路追踪示例。
diff --git a/metrics/probe/README.md b/metrics/probe/README.md
new file mode 100644
index 00000000..fc7d43ca
--- /dev/null
+++ b/metrics/probe/README.md
@@ -0,0 +1,166 @@
+
+# Dubbo-Go Kubernetes Probe Sample
+
+English | [中文](README_CN.md)
+
+This example demonstrates how to integrate **Kubernetes liveness, readiness, 
and startup probes** with a Dubbo-Go Triple service.
+
+It showcases how to expose dedicated probe endpoints and how Kubernetes reacts 
during application startup and warm-up.
+
+
+## Project Layout
+
+```
+metrics/probe/
+├── go-client/
+│   └── cmd/main.go        # Integration checker for ports/probes/RPC
+├── go-server/
+│   ├── cmd/main.go        # Application entrypoint
+│   ├── build.sh           # Docker build script
+│   └── Dockerfile         # Container image definition
+└── deploy/
+    └── server-deployment.yml  # Kubernetes deployment
+```
+
+
+## Default Configuration
+
+| Item                | Value                         |
+| ------------------- | ----------------------------- |
+| Triple service port | `20000`                       |
+| Probe HTTP port     | `22222`                       |
+| Probe endpoints     | `/live`, `/ready`, `/startup` |
+| Client target       | `tri://127.0.0.1:20000`       |
+
+### Probe Semantics
+
+* `GET /live`
+  Indicates whether the process is alive.
+
+* `GET /ready`
+  Indicates whether the service is ready to receive traffic.
+
+* `GET /startup`
+  Indicates whether the application startup phase has completed.
+
+
+## Run Locally
+
+### 1️Start the server
+
+```bash
+go run ./metrics/probe/go-server/cmd/main.go
+```
+
+### 2️Run the go-client integration checks
+
+```bash
+go run ./metrics/probe/go-client/cmd/main.go
+```
+
+The `go-client` validates:
+
+* Triple port `20000` is reachable.
+* Probe port `22222` is reachable.
+* `/live` returns `200`.
+* `/ready` and `/startup` eventually return `200` after warm-up.
+* One `Greet` RPC call succeeds.
+
+### 3️Monitor probe endpoints
+
+```bash
+watch -n 1 '
+for p in live ready startup; do
+  url="http://127.0.0.1:22222/$p";
+
+  body=$(curl -sS --max-time 2 "$url" 2>&1)
+  code=$(curl -s -o /dev/null --max-time 2 -w "%{http_code}" "$url" 
2>/dev/null)
+
+  printf "%-8s [%s] %s\n" "$p" "$code" "$body"
+done
+'
+```
+
+### Expected Behavior
+
+| Phase                | /live | /ready | /startup |
+| -------------------- | ----- | ------ | -------- |
+| Process started      | 200   | 503    | 503      |
+| During warm-up       | 200   | 503    | 503      |
+| After warm-up (~15s) | 200   | 200    | 200      |
+
+
+## Kubernetes Probe Configuration
+
+Example probe configuration:
+
+```yaml
+livenessProbe:
+  httpGet:
+    path: /live
+    port: 22222
+
+readinessProbe:
+  httpGet:
+    path: /ready
+    port: 22222
+
+startupProbe:
+  httpGet:
+    path: /startup
+    port: 22222
+```
+
+
+## Run on Kubernetes
+
+### Build the image
+
+From the repository root:
+
+```bash
+./metrics/probe/go-server/build.sh
+```
+
+
+### Load image into local cluster (if needed)
+
+For example, with Minikube:
+
+```bash
+minikube image load dubbo-go-probe-server:latest
+```
+
+
+### Deploy to Kubernetes
+
+```bash
+kubectl apply -f metrics/probe/deploy/server-deployment.yml
+kubectl rollout status deploy/dubbo-go-probe-server
+kubectl get pod -l app=dubbo-go-probe-server
+```
+
+
+### Inspect probe status
+
+```bash
+kubectl describe pod -l app=dubbo-go-probe-server
+```
+
+### Expected Kubernetes Behavior
+
+* Immediately after deployment:
+
+  * `Ready` = `False`
+  * `ContainersReady` = `False`
+
+* After ~15 seconds (warm-up completed):
+
+  * `Ready` = `True`
+  * `ContainersReady` = `True`
+
+This demonstrates proper separation of:
+
+* Process liveness
+* Service readiness
+* Startup lifecycle completion
diff --git a/metrics/probe/README_CN.md b/metrics/probe/README_CN.md
new file mode 100644
index 00000000..2678bc06
--- /dev/null
+++ b/metrics/probe/README_CN.md
@@ -0,0 +1,177 @@
+
+# Dubbo-Go Kubernetes 探针示例
+
+[English](README.md) | 中文
+
+
+本示例演示如何在 Dubbo-Go Triple 服务中集成 **Kubernetes 的 liveness、readiness 和 startup 
探针**。
+
+通过暴露独立的探针端点,可以清晰地观察应用启动、预热以及就绪阶段在 Kubernetes 中的行为。
+
+
+## 项目结构
+
+```
+metrics/probe/
+├── go-client/
+│   └── cmd/main.go              # 集成测试客户端(端口/探针/RPC 校验)
+├── go-server/
+│   ├── cmd/main.go              # 程序入口
+│   ├── build.sh                 # Docker 构建脚本
+│   └── Dockerfile               # 镜像定义文件
+└── deploy/
+    └── server-deployment.yml    # Kubernetes 部署文件
+```
+
+
+## 默认配置
+
+| 项目          | 默认值                           |
+| ----------- | ----------------------------- |
+| Triple 服务端口 | `20000`                       |
+| 探针 HTTP 端口  | `22222`                       |
+| 探针路径        | `/live`, `/ready`, `/startup` |
+| 客户端目标地址     | `tri://127.0.0.1:20000`       |
+
+
+## 探针语义说明
+
+* `GET /live`
+  表示进程是否存活(进程级健康检查)。
+
+* `GET /ready`
+  表示服务是否已准备好接收流量。
+
+* `GET /startup`
+  表示应用是否完成启动阶段。
+
+
+## 本地运行
+
+### 启动服务
+
+```bash
+go run ./metrics/probe/go-server/cmd/main.go
+```
+
+### 运行 go-client 做集成检查
+
+```bash
+go run ./metrics/probe/go-client/cmd/main.go
+```
+
+`go-client` 会依次检查:
+
+* Triple 端口 `20000` 可连接。
+* 探针端口 `22222` 可连接。
+* `/live` 返回 `200`。
+* `/ready`、`/startup` 在预热完成后返回 `200`。
+* 发起一次 `Greet` RPC,确认 Triple 服务可用。
+
+
+### 观察探针状态
+
+```bash
+watch -n 1 '
+for p in live ready startup; do
+  url="http://127.0.0.1:22222/$p";
+
+  body=$(curl -sS --max-time 2 "$url" 2>&1)
+  code=$(curl -s -o /dev/null --max-time 2 -w "%{http_code}" "$url" 
2>/dev/null)
+
+  printf "%-8s [%s] %s\n" "$p" "$code" "$body"
+done
+'
+```
+
+
+### 预期行为
+
+| 阶段           | /live | /ready | /startup |
+| ------------ | ----- | ------ | -------- |
+| 进程刚启动        | 200   | 503    | 503      |
+| 预热阶段         | 200   | 503    | 503      |
+| 预热完成(约 15 秒) | 200   | 200    | 200      |
+
+说明:
+
+* `/live` 只要进程未崩溃就返回 200。
+* `/ready` 与 `/startup` 在应用完成预热前返回 503。
+* 预热完成后,三个端点均返回 200。
+
+
+## Kubernetes 探针配置示例
+
+```yaml
+livenessProbe:
+  httpGet:
+    path: /live
+    port: 22222
+
+readinessProbe:
+  httpGet:
+    path: /ready
+    port: 22222
+
+startupProbe:
+  httpGet:
+    path: /startup
+    port: 22222
+```
+
+
+## 在 Kubernetes 中运行
+
+### 构建镜像
+
+在仓库根目录执行:
+
+```bash
+./metrics/probe/go-server/build.sh
+```
+
+
+### 将镜像加载到本地集群
+
+例如使用 Minikube:
+
+```bash
+minikube image load dubbo-go-probe-server:latest
+```
+
+
+### 部署到 Kubernetes
+
+```bash
+kubectl apply -f metrics/probe/deploy/server-deployment.yml
+kubectl rollout status deploy/dubbo-go-probe-server
+kubectl get pod -l app=dubbo-go-probe-server
+```
+
+
+### 查看探针状态
+
+```bash
+kubectl describe pod -l app=dubbo-go-probe-server
+```
+
+
+### 预期 Kubernetes 行为
+
+* 刚部署时:
+
+  * `Ready` = `False`
+  * `ContainersReady` = `False`
+
+* 约 15 秒后(预热完成):
+
+  * `Ready` = `True`
+  * `ContainersReady` = `True`
+
+这体现了:
+
+* 进程存活检查(Liveness)
+* 服务可用性检查(Readiness)
+* 启动阶段控制(Startup)
+
+三者的职责分离。
diff --git a/metrics/probe/deploy/server-deployment.yml 
b/metrics/probe/deploy/server-deployment.yml
new file mode 100644
index 00000000..62281fe1
--- /dev/null
+++ b/metrics/probe/deploy/server-deployment.yml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: dubbo-go-probe-server
+  labels:
+    app: dubbo-go-probe-server
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: dubbo-go-probe-server
+  template:
+    metadata:
+      labels:
+        app: dubbo-go-probe-server
+    spec:
+      containers:
+        - name: server
+          image: dubbo-go-probe-server:latest
+          imagePullPolicy: IfNotPresent
+          ports:
+            - containerPort: 20000
+              name: triple
+            - containerPort: 22222
+              name: probe
+          livenessProbe:
+            httpGet:
+              path: /live
+              port: probe
+            initialDelaySeconds: 5
+            periodSeconds: 10
+          readinessProbe:
+            httpGet:
+              path: /ready
+              port: probe
+            initialDelaySeconds: 5
+            periodSeconds: 5
+          startupProbe:
+            httpGet:
+              path: /startup
+              port: probe
+            failureThreshold: 30
+            periodSeconds: 1
diff --git a/metrics/probe/go-client/cmd/main.go 
b/metrics/probe/go-client/cmd/main.go
new file mode 100644
index 00000000..07249480
--- /dev/null
+++ b/metrics/probe/go-client/cmd/main.go
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+       "context"
+       "fmt"
+       "io"
+       "net"
+       "net/http"
+       "strings"
+       "time"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/client"
+       _ "dubbo.apache.org/dubbo-go/v3/imports"
+
+       "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+       greet "github.com/apache/dubbo-go-samples/direct/proto"
+)
+
+const (
+       tripleAddr   = "127.0.0.1:20000"
+       probeBaseURL = "http://127.0.0.1:22222";
+
+       tcpReadyTimeout   = 20 * time.Second
+       probeReadyTimeout = 40 * time.Second
+       requestTimeout    = 2 * time.Second
+)
+
+func main() {
+       ctx := context.Background()
+
+       if err := waitTCPReady(tripleAddr, tcpReadyTimeout); err != nil {
+               logger.Fatalf("triple port is not ready: %v", err)
+               panic("triple port is not ready")
+       }
+       logger.Infof("triple port is ready: %s", tripleAddr)
+
+       if err := waitTCPReady("127.0.0.1:22222", tcpReadyTimeout); err != nil {
+               logger.Fatalf("probe port is not ready: %v", err)
+               panic("probe port is not ready")
+       }
+       logger.Info("probe port is ready: 127.0.0.1:22222")
+
+       if err := expectHTTPStatus(probeBaseURL+"/live", http.StatusOK, 
requestTimeout); err != nil {
+               logger.Fatalf("/live check failed: %v", err)
+               panic("/live check failed")
+       }
+       logger.Info("/live is healthy")
+
+       if err := waitHTTPStatus(probeBaseURL+"/ready", http.StatusOK, 
probeReadyTimeout, requestTimeout); err != nil {
+               logger.Fatalf("/ready did not become healthy: %v", err)
+               panic("/ready did not become healthy")
+       }
+       logger.Info("/ready is healthy")
+
+       if err := waitHTTPStatus(probeBaseURL+"/startup", http.StatusOK, 
probeReadyTimeout, requestTimeout); err != nil {
+               logger.Fatalf("/startup did not become healthy: %v", err)
+               panic("/startup did not become healthy")
+       }
+       logger.Info("/startup is healthy")
+
+       if err := callGreet(ctx); err != nil {
+               logger.Fatalf("greet rpc check failed: %v", err)
+               panic("greet rpc check failed")
+       }
+       logger.Info("probe sample integration checks passed")
+}
+
+func callGreet(ctx context.Context) error {
+       cli, err := client.NewClient(
+               client.WithClientURL("tri://" + tripleAddr),
+       )
+       if err != nil {
+               return fmt.Errorf("create client: %w", err)
+       }
+
+       svc, err := greet.NewGreetService(cli)
+       if err != nil {
+               return fmt.Errorf("create greet service: %w", err)
+       }
+
+       rpcCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
+       defer cancel()
+
+       resp, err := svc.Greet(rpcCtx, &greet.GreetRequest{Name: "probe-check"})
+       if err != nil {
+               return fmt.Errorf("invoke greet: %w", err)
+       }
+       if strings.TrimSpace(resp.Greeting) == "" {
+               return fmt.Errorf("empty greet response")
+       }
+       logger.Infof("greet rpc succeeded: %s", resp.Greeting)
+       return nil
+}
+
+func waitTCPReady(addr string, timeout time.Duration) error {
+       deadline := time.Now().Add(timeout)
+       for {
+               conn, err := net.DialTimeout("tcp", addr, 1*time.Second)
+               if err == nil {
+                       _ = conn.Close()
+                       return nil
+               }
+               if time.Now().After(deadline) {
+                       return fmt.Errorf("tcp %s not ready within %s: %w", 
addr, timeout, err)
+               }
+               time.Sleep(300 * time.Millisecond)
+       }
+}
+
+func waitHTTPStatus(url string, expected int, timeout, reqTimeout 
time.Duration) error {
+       deadline := time.Now().Add(timeout)
+       var lastErr error
+       for {
+               err := expectHTTPStatus(url, expected, reqTimeout)
+               if err == nil {
+                       return nil
+               }
+               lastErr = err
+               if time.Now().After(deadline) {
+                       return fmt.Errorf("url %s not ready within %s: %w", 
url, timeout, lastErr)
+               }
+               time.Sleep(500 * time.Millisecond)
+       }
+}
+
+func expectHTTPStatus(url string, expected int, reqTimeout time.Duration) 
error {
+       client := http.Client{Timeout: reqTimeout}
+       resp, err := client.Get(url)
+       if err != nil {
+               return err
+       }
+       defer func() { _ = resp.Body.Close() }()
+
+       body, _ := io.ReadAll(resp.Body)
+       if resp.StatusCode != expected {
+               return fmt.Errorf("expect status %d but got %d, body=%s", 
expected, resp.StatusCode, strings.TrimSpace(string(body)))
+       }
+       return nil
+}
diff --git a/metrics/probe/go-server/Dockerfile 
b/metrics/probe/go-server/Dockerfile
new file mode 100644
index 00000000..c58271e5
--- /dev/null
+++ b/metrics/probe/go-server/Dockerfile
@@ -0,0 +1,6 @@
+FROM alpine:3.19
+WORKDIR /app
+COPY metrics/probe/go-server/probeApp /app/server
+
+EXPOSE 20000 22222
+ENTRYPOINT ["/app/server"]
diff --git a/metrics/go-server/build.sh b/metrics/probe/go-server/build.sh
similarity index 60%
copy from metrics/go-server/build.sh
copy to metrics/probe/go-server/build.sh
index 8b6c7bc1..d21e9afe 100644
--- a/metrics/go-server/build.sh
+++ b/metrics/probe/go-server/build.sh
@@ -1,3 +1,5 @@
+#!/bin/bash
+
 #
 #  Licensed to the Apache Software Foundation (ASF) under one or more
 #  contributor license agreements.  See the NOTICE file distributed with
@@ -14,7 +16,18 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-# if run on linux server use this
-#GOOS=linux GOARCH=arm64
-go build -o metricsApp cmd/main.go
-docker build . -t metrics-app:latest
\ No newline at end of file
+set -e
+
+echo "Building probe server image..."
+
+# Build from repository root.
+cd "$(dirname "$0")/../../.."
+
+# Build linux binary first. This uses local `replace => ../dubbo-go` if 
present.
+TARGET_OS=${TARGET_OS:-linux}
+TARGET_ARCH=${TARGET_ARCH:-amd64}
+
+CGO_ENABLED=0 GOOS="$TARGET_OS" GOARCH="$TARGET_ARCH" go build -o 
metrics/probe/go-server/probeApp ./metrics/probe/go-server/cmd/main.go
+docker build -f metrics/probe/go-server/Dockerfile -t 
dubbo-go-probe-server:latest .
+
+echo "Build completed successfully."
diff --git a/metrics/probe/go-server/cmd/main.go 
b/metrics/probe/go-server/cmd/main.go
new file mode 100644
index 00000000..9c907fdc
--- /dev/null
+++ b/metrics/probe/go-server/cmd/main.go
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+       "context"
+       "os"
+       "os/signal"
+       "sync/atomic"
+       "syscall"
+       "time"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3"
+       _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/metrics"
+       "dubbo.apache.org/dubbo-go/v3/metrics/probe"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
+       "dubbo.apache.org/dubbo-go/v3/server"
+
+       "github.com/dubbogo/gost/log/logger"
+
+       "github.com/pkg/errors"
+)
+
+import (
+       greet "github.com/apache/dubbo-go-samples/direct/proto"
+)
+
+const (
+       triplePort         = 20000
+       probePort          = 22222
+       probeLivenessPath  = "/live"
+       probeReadinessPath = "/ready"
+       probeStartupPath   = "/startup"
+       warmupSeconds      = 15
+)
+
+type ProbeGreetServer struct{}
+
+func (srv *ProbeGreetServer) Greet(_ context.Context, req *greet.GreetRequest) 
(*greet.GreetResponse, error) {
+       return &greet.GreetResponse{Greeting: "hello " + req.Name}, nil
+}
+
+func main() {
+       var warmupDone atomic.Bool
+       var dependencyReady atomic.Bool
+       dependencyReady.Store(true)
+
+       go func() {
+               logger.Infof("Warmup started, readiness/startup will fail for 
%ds", warmupSeconds)
+               time.Sleep(warmupSeconds * time.Second)
+               warmupDone.Store(true)
+               logger.Info("Warmup completed, readiness/startup should be 
healthy")
+       }()
+
+       probe.RegisterLiveness("process", func(ctx context.Context) error {
+               return nil
+       })
+       probe.RegisterReadiness("dependency", func(ctx context.Context) error {
+               if !dependencyReady.Load() {
+                       return errors.New("dependency not ready")
+               }
+               return nil
+       })
+       probe.RegisterReadiness("warmup", func(ctx context.Context) error {
+               if !warmupDone.Load() {
+                       return errors.New("warmup not complete")
+               }
+               return nil
+       })
+       probe.RegisterStartup("warmup", func(ctx context.Context) error {
+               if !warmupDone.Load() {
+                       return errors.New("startup warmup not complete")
+               }
+               return nil
+       })
+
+       ins, err := dubbo.NewInstance(
+               dubbo.WithMetrics(
+                       metrics.WithEnabled(),
+                       metrics.WithProbeEnabled(),
+                       metrics.WithProbePort(probePort),
+                       metrics.WithProbeLivenessPath(probeLivenessPath),
+                       metrics.WithProbeReadinessPath(probeReadinessPath),
+                       metrics.WithProbeStartupPath(probeStartupPath),
+                       metrics.WithProbeUseInternalState(true),
+               ),
+       )
+       if err != nil {
+               panic(err)
+       }
+
+       srv, err := ins.NewServer(
+               server.WithServerProtocol(
+                       protocol.WithTriple(),
+                       protocol.WithPort(triplePort),
+               ),
+       )
+       if err != nil {
+               panic(err)
+       }
+
+       if err := greet.RegisterGreetServiceHandler(srv, &ProbeGreetServer{}); 
err != nil {
+               panic(err)
+       }
+
+       stopCh := make(chan os.Signal, 1)
+       signal.Notify(stopCh, syscall.SIGINT, syscall.SIGTERM)
+
+       go func() {
+               logger.Infof("Probe sample server started, triple=%d probe=%d", 
triplePort, probePort)
+               if err := srv.Serve(); err != nil {
+                       logger.Error("Server error:", err)
+               }
+       }()
+
+       <-stopCh
+       logger.Info("Received shutdown signal, mark probe states to not ready")
+       dependencyReady.Store(false)
+       probe.SetReady(false)
+       probe.SetStartupComplete(false)
+
+       // Wait for test to complete
+       time.Sleep(3 * time.Second)
+}
diff --git a/metrics/Deployment.yml b/metrics/prometheus_grafana/Deployment.yml
similarity index 100%
rename from metrics/Deployment.yml
rename to metrics/prometheus_grafana/Deployment.yml
diff --git a/metrics/README.md b/metrics/prometheus_grafana/README.md
similarity index 98%
rename from metrics/README.md
rename to metrics/prometheus_grafana/README.md
index 7b09479b..fc8c0847 100644
--- a/metrics/README.md
+++ b/metrics/prometheus_grafana/README.md
@@ -76,7 +76,7 @@ First, start the Grafana, Prometheus, and Pushgateway 
services. We use `docker-c
 
 ```bash
 # Enter the metrics directory
-cd metrics
+cd metrics/prometheus_grafana
 # Start all monitoring services in the background
 docker-compose up -d
 ```
@@ -168,7 +168,7 @@ For 
details:[tools/pgw-cleaner](../tools/pgw-cleaner/README.md)
 
 - **Cannot connect to `host.docker.internal`**
 
-    - `host.docker.internal` is a built-in feature of Docker. If this address 
is not accessible, replace the IP address in `metrics/prometheus.yml` and the 
Grafana data source address with your actual IP address.
+    - `host.docker.internal` is a built-in feature of Docker. If this address 
is not accessible, replace the IP address in 
`metrics/prometheus_grafana/prometheus_pull.yml` and the Grafana data source 
address with your actual IP address.
 
 -----
 
diff --git a/metrics/README_CN.md b/metrics/prometheus_grafana/README_CN.md
similarity index 98%
rename from metrics/README_CN.md
rename to metrics/prometheus_grafana/README_CN.md
index 8bb2d5fb..9b7d8332 100644
--- a/metrics/README_CN.md
+++ b/metrics/prometheus_grafana/README_CN.md
@@ -79,7 +79,7 @@ go run ./go-server/cmd/main.go --push=false
 
 ```bash
 # 进入 metrics 目录
-cd metrics
+cd metrics/prometheus_grafana
 # 以后台模式启动所有监控服务
 docker-compose up -d
 ```
@@ -170,7 +170,7 @@ Pushgateway 设计初衷:为短生命周期进程(batch job、cron job)提
     - 在 Prometheus 的查询栏中输入 `dubbo_consumer_requests_succeed_total`,确认能查询到数据。
 
 - **`host.docker.internal` 无法连接**
-    - `host.docker.internal` 是 Docker 的内置功能,如果该地址无法访问,请将 
`metrics/prometheus.yml`
+    - `host.docker.internal` 是 Docker 的内置功能,如果该地址无法访问,请将 
`metrics/prometheus_grafana/prometheus_pull.yml`
       中的Ip地址以及Grafana的数据源地址换为实际的Ip地址。
 
 -----
diff --git a/metrics/assert/grafana.png 
b/metrics/prometheus_grafana/assert/grafana.png
similarity index 100%
rename from metrics/assert/grafana.png
rename to metrics/prometheus_grafana/assert/grafana.png
diff --git a/metrics/docker-compose.yml 
b/metrics/prometheus_grafana/docker-compose.yml
similarity index 100%
rename from metrics/docker-compose.yml
rename to metrics/prometheus_grafana/docker-compose.yml
diff --git a/metrics/go-client/Dockerfile 
b/metrics/prometheus_grafana/go-client/Dockerfile
similarity index 100%
rename from metrics/go-client/Dockerfile
rename to metrics/prometheus_grafana/go-client/Dockerfile
diff --git a/metrics/go-client/build.sh 
b/metrics/prometheus_grafana/go-client/build.sh
similarity index 100%
rename from metrics/go-client/build.sh
rename to metrics/prometheus_grafana/go-client/build.sh
diff --git a/metrics/go-client/cmd/main.go 
b/metrics/prometheus_grafana/go-client/cmd/main.go
similarity index 100%
rename from metrics/go-client/cmd/main.go
rename to metrics/prometheus_grafana/go-client/cmd/main.go
diff --git a/metrics/go-server/Dockerfile 
b/metrics/prometheus_grafana/go-server/Dockerfile
similarity index 100%
rename from metrics/go-server/Dockerfile
rename to metrics/prometheus_grafana/go-server/Dockerfile
diff --git a/metrics/go-server/build.sh 
b/metrics/prometheus_grafana/go-server/build.sh
similarity index 100%
rename from metrics/go-server/build.sh
rename to metrics/prometheus_grafana/go-server/build.sh
diff --git a/metrics/go-server/cmd/main.go 
b/metrics/prometheus_grafana/go-server/cmd/main.go
similarity index 100%
rename from metrics/go-server/cmd/main.go
rename to metrics/prometheus_grafana/go-server/cmd/main.go
diff --git a/metrics/grafana.json b/metrics/prometheus_grafana/grafana.json
similarity index 100%
rename from metrics/grafana.json
rename to metrics/prometheus_grafana/grafana.json
diff --git a/metrics/prometheus_pull.yml 
b/metrics/prometheus_grafana/prometheus_pull.yml
similarity index 100%
rename from metrics/prometheus_pull.yml
rename to metrics/prometheus_grafana/prometheus_pull.yml
diff --git a/metrics/prometheus_push.yml 
b/metrics/prometheus_grafana/prometheus_push.yml
similarity index 100%
rename from metrics/prometheus_push.yml
rename to metrics/prometheus_grafana/prometheus_push.yml
diff --git a/metrics/proto/greet.pb.go 
b/metrics/prometheus_grafana/proto/greet.pb.go
similarity index 98%
rename from metrics/proto/greet.pb.go
rename to metrics/prometheus_grafana/proto/greet.pb.go
index 4b9d164e..e1102c03 100644
--- a/metrics/proto/greet.pb.go
+++ b/metrics/prometheus_grafana/proto/greet.pb.go
@@ -139,7 +139,7 @@ const file_greet_proto_rawDesc = "" +
        "\rGreetResponse\x12\x1a\n" +
        "\bgreeting\x18\x01 \x01(\tR\bgreeting2D\n" +
        "\fGreetService\x124\n" +
-       
"\x05Greet\x12\x13.greet.GreetRequest\x1a\x14.greet.GreetResponse\"\x00B8Z6github.com/apache/dubbo-go-samples/metrics/proto;greetb\x06proto3"
+       
"\x05Greet\x12\x13.greet.GreetRequest\x1a\x14.greet.GreetResponse\"\x00B8Z6github.com/apache/dubbo-go-samples/metrics/prometheus_grafana/proto;greetb\x06proto3"
 
 var (
        file_greet_proto_rawDescOnce sync.Once
diff --git a/metrics/proto/greet.proto 
b/metrics/prometheus_grafana/proto/greet.proto
similarity index 96%
rename from metrics/proto/greet.proto
rename to metrics/prometheus_grafana/proto/greet.proto
index cb4df81a..9546a73e 100644
--- a/metrics/proto/greet.proto
+++ b/metrics/prometheus_grafana/proto/greet.proto
@@ -19,7 +19,7 @@ syntax = "proto3";
 
 package greet;
 
-option go_package = "github.com/apache/dubbo-go-samples/metrics/proto;greet";
+option go_package = 
"github.com/apache/dubbo-go-samples/metrics/prometheus_grafana/proto;greet";
 
 message GreetRequest {
   string name = 1;
diff --git a/metrics/proto/greet.triple.go 
b/metrics/prometheus_grafana/proto/greet.triple.go
similarity index 100%
rename from metrics/proto/greet.triple.go
rename to metrics/prometheus_grafana/proto/greet.triple.go
diff --git a/start_integrate_test.sh b/start_integrate_test.sh
index ac59d5bc..6666f31e 100755
--- a/start_integrate_test.sh
+++ b/start_integrate_test.sh
@@ -73,6 +73,9 @@ array+=("async")
 # error
 array+=("error")
 
+# metrics
+array+=("metrics/probe")
+
 # config_center
 array+=("config_center/nacos")
 # array+=("config_center/apollo")

Reply via email to