inital commit
This commit is contained in:
147
main.go
Normal file
147
main.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/XSAM/otelsql"
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/redis/go-redis/extra/redisotel/v9"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"go.opentelemetry.io/otel"
|
||||
)
|
||||
|
||||
// User представляет структуру пользователя.
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
var (
|
||||
db *sql.DB
|
||||
rdb *redis.Client
|
||||
tracer = otel.Tracer("redis_example")
|
||||
)
|
||||
|
||||
// initDB инициализирует подключение к базе данных.
|
||||
func initDB() error {
|
||||
var err error
|
||||
connStr := "postgres://user:password@localhost/mydb?sslmode=disable"
|
||||
db, err = otelsql.Open("postgres", connStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ошибка подключения к БД: %v", err)
|
||||
}
|
||||
return db.Ping()
|
||||
}
|
||||
|
||||
// initRedis инициализирует подключение к Redis/KeyDB.
|
||||
func initRedis() {
|
||||
rdb = redis.NewClient(&redis.Options{
|
||||
Addr: "localhost:6379",
|
||||
})
|
||||
if err := redisotel.InstrumentTracing(rdb); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// getUserByID возвращает пользователя из БД по ID, с кешированием в Redis.
|
||||
func getUserByID(ctx context.Context, id int) (*User, error) {
|
||||
ctxLocal, span := tracer.Start(ctx, "getUserByID")
|
||||
defer span.End()
|
||||
|
||||
// Пытаемся получить данные из кеша.
|
||||
cachedUser, err := rdb.Get(ctxLocal, strconv.Itoa(id)).Result()
|
||||
if err == nil {
|
||||
var user User
|
||||
if err := json.Unmarshal([]byte(cachedUser), &user); err == nil {
|
||||
return &user, nil
|
||||
}
|
||||
}
|
||||
|
||||
var user User
|
||||
query := "SELECT id, name, age FROM users WHERE id = $1"
|
||||
err = db.QueryRowContext(ctxLocal, query, id).Scan(&user.ID, &user.Name, &user.Age)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil // пользователь не найден
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("ошибка запроса: %v", err)
|
||||
}
|
||||
|
||||
// Сохраняем результаты в кеш.
|
||||
encodedUser, err := json.Marshal(user)
|
||||
if err == nil {
|
||||
rdb.Set(ctxLocal, strconv.Itoa(user.ID), encodedUser, time.Second*10)
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// userHandler обрабатывает запросы для получения пользователя.
|
||||
func userHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctxLocal, span := tracer.Start(r.Context(), "handler")
|
||||
defer span.End()
|
||||
|
||||
ids := r.URL.Query().Get("id")
|
||||
if ids == "" {
|
||||
http.Error(w, "id не указан", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.Atoi(ids)
|
||||
if err != nil {
|
||||
http.Error(w, "id должен быть числом", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := getUserByID(ctxLocal, id)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("ошибка получения пользователя: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
http.Error(w, "пользователь не найден", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(user); err != nil {
|
||||
http.Error(w, fmt.Sprintf("ошибка кодирования ответа: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
shutdown, err := InstallExportPipeline()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
defer func() {
|
||||
if err := shutdown(context.Background()); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
// Инициализируем подключение к БД.
|
||||
if err := initDB(); err != nil {
|
||||
log.Fatalf("не удалось инициализировать БД: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Инициализируем подключение к Redis.
|
||||
initRedis()
|
||||
defer rdb.Close()
|
||||
|
||||
// Регистрируем обработчик.
|
||||
http.HandleFunc("/user", userHandler)
|
||||
|
||||
// Запускаем сервер.
|
||||
fmt.Println("Сервер запущен на :8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
Reference in New Issue
Block a user