mirror of
https://github.com/oarkflow/mq.git
synced 2025-09-26 20:11:16 +08:00
update: HTTP API
This commit is contained in:
141
consumer.go
141
consumer.go
@@ -3,8 +3,10 @@ package mq
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -253,6 +255,14 @@ func (c *Consumer) Consume(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to connect to server for queue %s: %v", c.queue, err)
|
||||
}
|
||||
c.pool.Start(c.opts.numOfWorkers)
|
||||
if c.opts.enableHTTPApi {
|
||||
go func() {
|
||||
_, err := c.StartHTTPAPI()
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("Error on running HTTP API %s", err.Error()))
|
||||
}
|
||||
}()
|
||||
}
|
||||
// Infinite loop to continuously read messages and reconnect if needed.
|
||||
for {
|
||||
select {
|
||||
@@ -341,3 +351,134 @@ func (c *Consumer) sendOpsMessage(ctx context.Context, cmd consts.CMD) error {
|
||||
func (c *Consumer) Conn() net.Conn {
|
||||
return c.conn
|
||||
}
|
||||
|
||||
// StartHTTPAPI starts an HTTP server on a random available port and registers API endpoints.
|
||||
// It returns the port number the server is listening on.
|
||||
func (c *Consumer) StartHTTPAPI() (int, error) {
|
||||
// Listen on a random port.
|
||||
ln, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to start listener: %w", err)
|
||||
}
|
||||
port := ln.Addr().(*net.TCPAddr).Port
|
||||
|
||||
// Create a new HTTP mux and register endpoints.
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/stats", c.handleStats)
|
||||
mux.HandleFunc("/update", c.handleUpdate)
|
||||
mux.HandleFunc("/pause", c.handlePause)
|
||||
mux.HandleFunc("/resume", c.handleResume)
|
||||
mux.HandleFunc("/stop", c.handleStop)
|
||||
|
||||
// Start the server in a new goroutine.
|
||||
go func() {
|
||||
// Log errors if the HTTP server stops.
|
||||
if err := http.Serve(ln, mux); err != nil {
|
||||
log.Printf("HTTP server error on port %d: %v", port, err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Printf("HTTP API for consumer %s started on port %d", c.id, port)
|
||||
return port, nil
|
||||
}
|
||||
|
||||
// handleStats responds with JSON containing consumer and pool metrics.
|
||||
func (c *Consumer) handleStats(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Gather consumer and pool stats using formatted metrics.
|
||||
stats := map[string]interface{}{
|
||||
"consumer_id": c.id,
|
||||
"queue": c.queue,
|
||||
"pool_metrics": c.pool.FormattedMetrics(),
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(stats); err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to encode stats: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
// handleUpdate accepts a POST request with a JSON payload to update the consumer's pool configuration.
|
||||
// It reuses the consumer's Update method which updates the pool configuration.
|
||||
func (c *Consumer) handleUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Read the request body.
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to read request body: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
// Call the Update method on the consumer (which in turn updates the pool configuration).
|
||||
if err := c.Update(r.Context(), body); err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to update configuration: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
resp := map[string]string{"status": "configuration updated"}
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to encode response: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
// handlePause pauses the consumer's pool.
|
||||
func (c *Consumer) handlePause(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.Pause(r.Context()); err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to pause consumer: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
resp := map[string]string{"status": "consumer paused"}
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
// handleResume resumes the consumer's pool.
|
||||
func (c *Consumer) handleResume(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.Resume(r.Context()); err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to resume consumer: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
resp := map[string]string{"status": "consumer resumed"}
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
// handleStop stops the consumer's pool.
|
||||
func (c *Consumer) handleStop(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Stop the consumer.
|
||||
if err := c.Stop(r.Context()); err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to stop consumer: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
resp := map[string]string{"status": "consumer stopped"}
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
Reference in New Issue
Block a user