package async import ( "context" "encoding/json" "fmt" "time" "github.com/redis/go-redis/v9" ) const ( TaskEventQueueKey = "task_center:events:queue" ) type EventType string const ( EventTypeOrderPaid EventType = "order_paid" EventTypeInviteSuccess EventType = "invite_success" ) type TaskEvent struct { Type EventType `json:"type"` Payload string `json:"payload"` CreatedAt int64 `json:"created_at"` } type OrderPaidPayload struct { UserID int64 `json:"user_id"` OrderID int64 `json:"order_id"` } type InviteSuccessPayload struct { InviterID int64 `json:"inviter_id"` InviteeID int64 `json:"invitee_id"` } type TaskQueue interface { PublishOrderPaid(ctx context.Context, userID, orderID int64) error PublishInviteSuccess(ctx context.Context, inviterID, inviteeID int64) error Consume(ctx context.Context) (*TaskEvent, error) } type redisTaskQueue struct { client *redis.Client } func NewRedisTaskQueue(client *redis.Client) TaskQueue { return &redisTaskQueue{client: client} } func (q *redisTaskQueue) PublishOrderPaid(ctx context.Context, userID, orderID int64) error { payload, _ := json.Marshal(OrderPaidPayload{UserID: userID, OrderID: orderID}) event := TaskEvent{ Type: EventTypeOrderPaid, Payload: string(payload), CreatedAt: time.Now().Unix(), } bytes, _ := json.Marshal(event) return q.client.LPush(ctx, TaskEventQueueKey, bytes).Err() } func (q *redisTaskQueue) PublishInviteSuccess(ctx context.Context, inviterID, inviteeID int64) error { payload, _ := json.Marshal(InviteSuccessPayload{InviterID: inviterID, InviteeID: inviteeID}) event := TaskEvent{ Type: EventTypeInviteSuccess, Payload: string(payload), CreatedAt: time.Now().Unix(), } bytes, _ := json.Marshal(event) return q.client.LPush(ctx, TaskEventQueueKey, bytes).Err() } func (q *redisTaskQueue) Consume(ctx context.Context) (*TaskEvent, error) { // Block for 2 seconds result, err := q.client.BRPop(ctx, 2*time.Second, TaskEventQueueKey).Result() if err != nil { if err == redis.Nil { return nil, nil // Timeout, no message } return nil, err } if len(result) < 2 { return nil, fmt.Errorf("invalid redis result") } var event TaskEvent if err := json.Unmarshal([]byte(result[1]), &event); err != nil { return nil, err } return &event, nil }