Reputation: 477
I have 2 buffered channels servicing inbound requests:
rabbitQ = make(chan map[string]interface{}, 1000)
sqsQ = make (chan map[string]interface{}, 1000)
My dispatcher function looks like this:
func dispatchMessage(params map[string]interface{}) {
if !shouldFailoverToSQS {
select {
case rabbitQ <- params:
sentToRabbitMQ++
case sqsQ <- params:
sentToSQS++
default:
log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
}
} else {
sqsQ <- params
}
}
I would expect that messages would always be sent to rabbitQ unless the buffer was at capacity but I'm finding that the call is falling through and sending messages to sqsQ about half the time. This is not what I want - I only want to send to sqsQ if rabbitQ is full.
How can I enforce this?
Upvotes: 1
Views: 522
Reputation: 3859
func dispatchMessage(params map[string]interface{}) {
if !shouldFailoverToSQS {
select {
case rabbitQ <- params:
sentToRabbitMQ++
case <-time.After(time.Millisecond * 10.0): // rabbit is blocked and 10 milli sec passed.
select {
case sqsQ <- params:
sentToSQS++
default:
log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
}
}
} else {
sqsQ <- params
}
}
Upvotes: 0
Reputation: 2215
For a concise answer (it looks like you already have it from your answer + the thread comment), your select will choose at random. Per the docs:
If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
In addition, I figured I would provide you with an answer that doesn't use selects at all. Using len, you can determine how many values are queued up in a channel. Sure it's no different than what you're doing now, but I figured I would offer something different:
const MaxChan = 1000
func dispatchMessage(params map[string]interface{}) {
if !shouldFailoverToSQS {
if len(rabbitQ) < MaxChan {
sentToRabbitMQ++
} else if len(sqsQ) < MaxChan {
sentToSQS++
} else {
log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
}
} else {
if len(sqsQ) < MaxChan {
sentToRabbitMQ++
} else if len(rabbitQ) < MaxChan {
sentToSQS++
} else {
log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
}
}
}
Supporting docs: https://golang.org/ref/spec#Select_statements
Upvotes: 0
Reputation: 477
Per Voker's comment, this is what I came up with:
func dispatchMessage(params map[string]interface{}) {
//log.Debugf("Failover: %t, Len: %d", shouldFailoverToSQS, len(rabbitQ))
if !shouldFailoverToSQS {
select {
case rabbitQ <- params:
sentToRabbitMQ++
default:
select {
case sqsQ <- params:
sentToSQS++
default:
log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
}
}
} else {
select {
case sqsQ <- params:
sentToSQS++
default:
log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
}
}
}
Upvotes: 1