Chúng tôi khuyên bạn nên sử dụng các công cụ giám sát như Prometheus để giám sát các quá trình và hàng đợi công việc của bạn trong môi trường sản xuất.
Đo lường Hàng đợi
Nếu bạn đang sử dụng Giao diện người dùng Web, bạn có thể kích hoạt tích hợp với Prometheus bằng cách cung cấp hai tham số:
-
--enable-metrics-exporter
: Kích hoạt việc thu thập số liệu hàng đợi và xuất chúng đến điểm cuối/metrics
. -
--prometheus-addr
: Kích hoạt hiển thị số liệu hàng đợi trong giao diện người dùng Web.
Trang số liệu hàng đợi trông như sau:
Nếu bạn không sử dụng Giao diện người dùng Web, Asynq đi kèm với một tệp nhị phân mà bạn có thể chạy để xuất số liệu hàng đợi. Nó cũng bao gồm một package x/metrics
để thu thập số liệu hàng đợi.
Đo lường Quá trình Công việc
Giao diện Handler
và ServeMux
của Asynq có thể được trang bị với số liệu hàng đợi để quan sát.
Dưới đây là một ví dụ về việc xuất số liệu quá trình công việc bằng cách sử dụng Prometheus. Chúng ta có thể trang bị mã của mình trong ứng dụng để theo dõi các số liệu ứng dụng cụ thể, cũng như các số liệu mặc định (như bộ nhớ và CPU) được theo dõi bởi Prometheus.
Dưới đây là danh sách các số liệu cụ thể của ứng dụng được theo dõi trong mã ví dụ:
- Tổng số công việc xử lý bởi quá trình công việc (bao gồm cả công việc thành công và thất bại).
- Số công việc thất bại được xử lý bởi quá trình công việc.
- Số công việc hiện tại đang được xử lý bởi quá trình công việc.
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"runtime"
"github.com/hibiken/asynq"
"github.com/hibiken/asynq/examples/tasks"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/sys/unix"
)
// Các biến số liệu.
var (
processedCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "processed_tasks_total",
Help: "Tổng số công việc đã xử lý",
},
[]string{"task_type"},
)
failedCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "failed_tasks_total",
Help: "Tổng số công việc thất bại đã được xử lý",
},
[]string{"task_type"},
)
inProgressGauge = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: "in_progress_tasks",
Help: "Số công việc hiện tại đang được xử lý",
},
[]string{"task_type"},
)
)
func metricsMiddleware(next asynq.Handler) asynq.Handler {
return asynq.HandlerFunc(func(ctx context.Context, t *asynq.Task) error {
inProgressGauge.WithLabelValues(t.Type()).Inc()
err := next.ProcessTask(ctx, t)
inProgressGauge.WithLabelValues(t.Type()).Dec()
if err != nil {
failedCounter.WithLabelValues(t.Type()).Inc()
}
processedCounter.WithLabelValues(t.Type()).Inc()
return err
})
}
func main() {
httpServeMux := http.NewServeMux()
httpServeMux.Handle("/metrics", promhttp.Handler())
metricsSrv := &http.Server{
Addr: ":2112",
Handler: httpServeMux,
}
done := make(chan struct{})
// Bắt đầu máy chủ số liệu.
go func() {
err := metricsSrv.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
log.Printf("Lỗi: máy chủ số liệu bị lỗi: %v", err)
}
close(done)
}()
srv := asynq.NewServer(
asynq.RedisClientOpt{Addr: ":6379"},
asynq.Config{Concurrency: 20},
)
mux := asynq.NewServeMux()
mux.Use(metricsMiddleware)
mux.HandleFunc(tasks.TypeEmail, tasks.HandleEmailTask)
// Khởi động máy chủ worker.
if err := srv.Start(mux); err != nil {
log.Fatalf("Không thể khởi động máy chủ worker: %v", err)
}
// Chờ tín hiệu kết thúc.
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, unix.SIGTERM, unix.SIGINT)
}