-
Notifications
You must be signed in to change notification settings - Fork 145
/
msgqueue.go
171 lines (128 loc) · 4.06 KB
/
msgqueue.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package msgqueue
import (
"context"
"fmt"
)
type Queue interface {
// Name returns the name of the queue.
Name() string
// Durable returns true if this queue should survive task queue restarts.
Durable() bool
// AutoDeleted returns true if this queue should be deleted when the last consumer unsubscribes.
AutoDeleted() bool
// Exclusive returns true if this queue should only be accessed by the current connection.
Exclusive() bool
// FanoutExchangeKey returns which exchange the queue should be subscribed to. This is only currently relevant
// to tenant pub/sub queues.
//
// In RabbitMQ terminology, the existence of a subscriber key means that the queue is bound to a fanout
// exchange, and a new random queue is generated for each connection when connections are retried.
FanoutExchangeKey() string
// DLX returns the dead letter exchange for the queue, if it exists.
DLX() string
}
type staticQueue string
const (
EVENT_PROCESSING_QUEUE staticQueue = "event_processing_queue_v2"
JOB_PROCESSING_QUEUE staticQueue = "job_processing_queue_v2"
WORKFLOW_PROCESSING_QUEUE staticQueue = "workflow_processing_queue_v2"
DISPATCHER_POOL_QUEUE staticQueue = "dispatcher_pool_queue_v2"
SCHEDULING_QUEUE staticQueue = "scheduling_queue_v2"
)
func (s staticQueue) Name() string {
return string(s)
}
func (s staticQueue) Durable() bool {
return true
}
func (s staticQueue) AutoDeleted() bool {
return false
}
func (s staticQueue) Exclusive() bool {
return false
}
func (s staticQueue) FanoutExchangeKey() string {
return ""
}
func (s staticQueue) DLX() string {
return fmt.Sprintf("%s_dlx_v2", s.Name())
}
type consumerQueue string
func (s consumerQueue) Name() string {
return string(s)
}
func (n consumerQueue) Durable() bool {
return false
}
func (n consumerQueue) AutoDeleted() bool {
return true
}
func (n consumerQueue) Exclusive() bool {
return true
}
func (n consumerQueue) FanoutExchangeKey() string {
return ""
}
func (n consumerQueue) DLX() string {
return ""
}
func QueueTypeFromDispatcherID(d string) consumerQueue {
return consumerQueue(d)
}
func QueueTypeFromTickerID(t string) consumerQueue {
return consumerQueue(t)
}
type fanoutQueue struct {
consumerQueue
}
// The fanout exchange key for a consumer is the name of the consumer queue.
func (f fanoutQueue) FanoutExchangeKey() string {
return f.consumerQueue.Name()
}
func TenantEventConsumerQueue(t string) (fanoutQueue, error) {
// generate a unique queue name for the tenant
return fanoutQueue{
consumerQueue: consumerQueue(t),
}, nil
}
type Message struct {
// ID is the ID of the task.
ID string `json:"id"`
// Payload is the payload of the task.
Payload map[string]interface{} `json:"payload"`
// Metadata is the metadata of the task.
Metadata map[string]interface{} `json:"metadata"`
// Retries is the number of retries for the task.
Retries int `json:"retries"`
// RetryDelay is the delay between retries.
RetryDelay int `json:"retry_delay"`
}
func (t *Message) TenantID() string {
tenantId, exists := t.Metadata["tenant_id"]
if !exists {
return ""
}
tenantIdStr, ok := tenantId.(string)
if !ok {
return ""
}
return tenantIdStr
}
type AckHook func(task *Message) error
type MessageQueue interface {
// AddMessage adds a task to the queue
AddMessage(ctx context.Context, queue Queue, task *Message) error
// Subscribe subscribes to the task queue. It returns a cleanup function that should be called when the
// subscription is no longer needed.
Subscribe(queue Queue, preAck AckHook, postAck AckHook) (func() error, error)
// RegisterTenant registers a new pub/sub mechanism for a tenant. This should be called when a
// new tenant is created. If this is not called, implementors should ensure that there's a check
// on the first message to a tenant to ensure that the tenant is registered, and store the tenant
// in an LRU cache which lives in-memory.
RegisterTenant(ctx context.Context, tenantId string) error
// IsReady returns true if the task queue is ready to accept tasks.
IsReady() bool
}
func NoOpHook(task *Message) error {
return nil
}