feat: rabbitMQ request

This commit is contained in:
Iron_Felix 2025-11-30 01:34:59 +03:00
parent a25a912ead
commit c6cebb0ed2
6 changed files with 125 additions and 1 deletions

103
modules/backend/rabbit.go Normal file
View file

@ -0,0 +1,103 @@
package main
import (
"context"
"encoding/json"
"fmt"
oapi "nyanimedb/api"
"time"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"github.com/streadway/amqp"
)
type RabbitRequest struct {
Name string `json:"name"`
Status oapi.TitleStatus `json:"titlestatus,omitempty"`
Rating float64 `json:"titleraring,omitempty"`
Year int32 `json:"year,omitempty"`
Season oapi.ReleaseSeason `json:"season,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
// PublishAndAwaitReply отправляет запрос и ждёт ответа от workerа.
// Возвращает раскодированный ответ или ошибку.
func PublishAndAwaitReply(
ctx context.Context,
ch *amqp.Channel,
requestQueue string, // например: "svc.media.process.requests"
request RabbitRequest, // ваша структура запроса
replyCh chan<- any, // куда положить ответ (вы читаете извне)
) error {
// 1. Создаём временную очередь для ответов
replyQueue, err := ch.QueueDeclare(
"", // auto-generated name
false, // not durable
true, // exclusive
true, // auto-delete
false, // no-wait
nil,
)
if err != nil {
return fmt.Errorf("failed to declare reply queue: %w", err)
}
// 2. Готовим корреляционный ID
corrID := uuid.New().String() // ← используйте github.com/google/uuid
logrus.Infof("New CorrID: %s", corrID)
// 3. Сериализуем запрос
body, err := json.Marshal(request)
if err != nil {
return fmt.Errorf("failed to marshal request: %w", err)
}
// 4. Публикуем запрос
err = ch.Publish(
"", // default exchange (или свой, если используете)
requestQueue,
false,
false,
amqp.Publishing{
ContentType: "application/json",
CorrelationId: corrID,
ReplyTo: replyQueue.Name,
DeliveryMode: amqp.Persistent,
Timestamp: time.Now(),
Body: body,
},
)
if err != nil {
return fmt.Errorf("failed to publish request, corrID: %s : %w", corrID, err)
}
// 5. Подписываемся на ответы
msgs, err := ch.Consume(
replyQueue.Name,
"", // consumer tag
true, // auto-ack
true, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
if err != nil {
return fmt.Errorf("failed to consume from reply queue: %w", err)
}
// 6. Ожидаем ответ с таймаутом
select {
case msg := <-msgs:
if msg.CorrelationId != corrID {
return fmt.Errorf("correlation ID mismatch: got %s, expected %s", msg.CorrelationId, corrID)
}
// Десериализуем — тут можно передать target-структуру или использовать interface{}
// В данном случае просто возвращаем байты или пусть вызывающая сторона парсит
replyCh <- msg.Body // или json.Unmarshal → и отправить структуру в канал
return nil
case <-ctx.Done():
return ctx.Err()
}
}