v0.0.18.5 замена ws на sse
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
f9e9347389
commit
2a3ae72db9
@ -121,45 +121,29 @@ func (r *queryResolver) GetUserChats(ctx context.Context, userID int) ([]*domain
|
|||||||
|
|
||||||
// MessageStream реализация подписки на новые сообщения
|
// MessageStream реализация подписки на новые сообщения
|
||||||
func (r *subscriptionResolver) MessageStream(ctx context.Context, userID int) (<-chan *domain.Message, error) {
|
func (r *subscriptionResolver) MessageStream(ctx context.Context, userID int) (<-chan *domain.Message, error) {
|
||||||
messageChan := make(chan *domain.Message, 10) // Буферизованный канал
|
// Создаем канал для GraphQL подписки
|
||||||
|
messageChan := make(chan *domain.Message)
|
||||||
|
|
||||||
go func() {
|
// Вызываем gRPC стриминг
|
||||||
defer close(messageChan)
|
|
||||||
retryCount := 0
|
|
||||||
maxRetries := 5
|
|
||||||
|
|
||||||
for {
|
|
||||||
if retryCount >= maxRetries {
|
|
||||||
log.Printf("Max retries (%d) reached for user %d", maxRetries, userID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Создаем новое соединение
|
|
||||||
stream, err := r.MessageClient.StreamMessages(ctx, &proto.StreamMessagesRequest{
|
stream, err := r.MessageClient.StreamMessages(ctx, &proto.StreamMessagesRequest{
|
||||||
UserId: int32(userID),
|
UserId: int32(userID),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Stream connection error for user %d: %v (retry %d)", userID, err, retryCount)
|
return nil, fmt.Errorf("failed to stream messages: %w", err)
|
||||||
retryCount++
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case <-time.After(time.Duration(retryCount) * time.Second):
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retryCount = 0 // Сброс счетчика при успешном подключении
|
go func() {
|
||||||
|
defer close(messageChan)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
msg, err := stream.Recv()
|
msg, err := stream.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Stream receive error for user %d: %v", userID, err)
|
log.Printf("gRPC stream error: %v", err)
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Пропускаем heartbeat сообщения
|
// Пропускаем heartbeat сообщения
|
||||||
if msg.Message.GetContent() == "__heartbeat__" {
|
if msg.Message.Content == "__heartbeat__" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,16 +151,6 @@ func (r *subscriptionResolver) MessageStream(ctx context.Context, userID int) (<
|
|||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case messageChan <- protoMessageToDomain(msg.Message):
|
case messageChan <- protoMessageToDomain(msg.Message):
|
||||||
// Сообщение успешно отправлено в канал
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Пауза перед повторной попыткой
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case <-time.After(1 * time.Second):
|
|
||||||
retryCount++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -186,9 +160,6 @@ func (r *subscriptionResolver) MessageStream(ctx context.Context, userID int) (<
|
|||||||
|
|
||||||
// Преобразование proto-сообщения в domain-модель
|
// Преобразование proto-сообщения в domain-модель
|
||||||
func protoMessageToDomain(msg *proto.Message) *domain.Message {
|
func protoMessageToDomain(msg *proto.Message) *domain.Message {
|
||||||
if msg == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &domain.Message{
|
return &domain.Message{
|
||||||
ID: int(msg.Id),
|
ID: int(msg.Id),
|
||||||
ChatID: int(msg.ChatId),
|
ChatID: int(msg.ChatId),
|
||||||
|
|||||||
@ -5,10 +5,9 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"github.com/99designs/gqlgen/graphql/handler"
|
"github.com/99designs/gqlgen/graphql/handler"
|
||||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||||
"github.com/99designs/gqlgen/graphql/playground"
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -72,26 +71,29 @@ func (s *Server) configureRouter() {
|
|||||||
Resolvers: resolver,
|
Resolvers: resolver,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
wsTransport := transport.Websocket{
|
srv.AddTransport(&transport.POST{})
|
||||||
Upgrader: websocket.Upgrader{
|
srv.AddTransport(&transport.GET{})
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
srv.AddTransport(&transport.Options{})
|
||||||
origin := r.Header.Get("Origin")
|
|
||||||
for _, allowed := range allowedOrigins {
|
|
||||||
if origin == allowed {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
srv.AddTransport(&wsTransport)
|
// Настройка SSE транспорта (правильный способ)
|
||||||
|
sseTransport := &transport.SSE{}
|
||||||
|
srv.AddTransport(sseTransport)
|
||||||
|
|
||||||
|
// Простейший кеш запросов (альтернатива MemoryCache)
|
||||||
|
srv.SetQueryCache(&NoopCache{})
|
||||||
|
})
|
||||||
|
|
||||||
s.router.Handle("/", playground.Handler("GraphQL playground", "/query"))
|
s.router.Handle("/", playground.Handler("GraphQL playground", "/query"))
|
||||||
s.router.Handle("/query", srv)
|
s.router.Handle("/query", srv)
|
||||||
s.router.Handle("/uploads/*", http.StripPrefix("/uploads/", http.FileServer(http.Dir("./uploads"))))
|
s.router.Handle("/uploads/*", http.StripPrefix("/uploads/", http.FileServer(http.Dir("./uploads"))))
|
||||||
}
|
}
|
||||||
|
type NoopCache struct{}
|
||||||
|
|
||||||
|
func (n *NoopCache) Get(ctx context.Context, key string) (*ast.QueryDocument, bool) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NoopCache) Add(ctx context.Context, key string, value *ast.QueryDocument) {}
|
||||||
|
|
||||||
func (s *Server) configureMetrics() {
|
func (s *Server) configureMetrics() {
|
||||||
metricsRouter := chi.NewRouter()
|
metricsRouter := chi.NewRouter()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user