-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds consumer metadata checking to next requests #5141
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2965,36 +2965,36 @@ func (o *consumer) needAck(sseq uint64, subj string) bool { | |
} | ||
|
||
// Helper for the next message requests. | ||
func nextReqFromMsg(msg []byte) (time.Time, int, int, bool, time.Duration, time.Time, error) { | ||
func nextReqFromMsg(msg []byte) (time.Time, int, int, bool, time.Duration, time.Time, map[string]string, error) { | ||
req := bytes.TrimSpace(msg) | ||
|
||
switch { | ||
case len(req) == 0: | ||
return time.Time{}, 1, 0, false, 0, time.Time{}, nil | ||
return time.Time{}, 1, 0, false, 0, time.Time{}, nil, nil | ||
|
||
case req[0] == '{': | ||
var cr JSApiConsumerGetNextRequest | ||
if err := json.Unmarshal(req, &cr); err != nil { | ||
return time.Time{}, -1, 0, false, 0, time.Time{}, err | ||
return time.Time{}, -1, 0, false, 0, time.Time{}, nil, err | ||
} | ||
var hbt time.Time | ||
if cr.Heartbeat > 0 { | ||
if cr.Heartbeat*2 > cr.Expires { | ||
return time.Time{}, 1, 0, false, 0, time.Time{}, errors.New("heartbeat value too large") | ||
return time.Time{}, 1, 0, false, 0, time.Time{}, nil, errors.New("heartbeat value too large") | ||
} | ||
hbt = time.Now().Add(cr.Heartbeat) | ||
} | ||
if cr.Expires == time.Duration(0) { | ||
return time.Time{}, cr.Batch, cr.MaxBytes, cr.NoWait, cr.Heartbeat, hbt, nil | ||
return time.Time{}, cr.Batch, cr.MaxBytes, cr.NoWait, cr.Heartbeat, hbt, nil, nil | ||
} | ||
return time.Now().Add(cr.Expires), cr.Batch, cr.MaxBytes, cr.NoWait, cr.Heartbeat, hbt, nil | ||
return time.Now().Add(cr.Expires), cr.Batch, cr.MaxBytes, cr.NoWait, cr.Heartbeat, hbt, cr.Metadata, nil | ||
default: | ||
if n, err := strconv.Atoi(string(req)); err == nil { | ||
return time.Time{}, n, 0, false, 0, time.Time{}, nil | ||
return time.Time{}, n, 0, false, 0, time.Time{}, nil, nil | ||
} | ||
} | ||
|
||
return time.Time{}, 1, 0, false, 0, time.Time{}, nil | ||
return time.Time{}, 1, 0, false, 0, time.Time{}, nil, nil | ||
} | ||
|
||
// Represents a request that is on the internal waiting queue | ||
|
@@ -3310,7 +3310,7 @@ func (o *consumer) processNextMsgRequest(reply string, msg []byte) { | |
} | ||
|
||
// Check payload here to see if they sent in batch size or a formal request. | ||
expires, batchSize, maxBytes, noWait, hb, hbt, err := nextReqFromMsg(msg) | ||
expires, batchSize, maxBytes, noWait, hb, hbt, consumerMetaData, err := nextReqFromMsg(msg) | ||
if err != nil { | ||
sendErr(400, fmt.Sprintf("Bad Request - %v", err)) | ||
return | ||
|
@@ -3332,6 +3332,26 @@ func (o *consumer) processNextMsgRequest(reply string, msg []byte) { | |
return | ||
} | ||
|
||
if len(consumerMetaData) > 0 && len(o.cfg.Metadata) > 0 { | ||
var matching = true | ||
for k, v := range consumerMetaData { | ||
configValue, ok := o.cfg.Metadata[k] | ||
if ok { | ||
if configValue != v { | ||
matching = false | ||
break | ||
} | ||
} else { | ||
matching = false | ||
break | ||
} | ||
} | ||
if !matching { | ||
sendErr(409, "Request's medata does not match the consumer's") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should to be the same error code. I would really like us to have separate code's at least for errors that have a very distinct way to react to them in the client. Also this should be a const, not a literal. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just did the same as what the existing other 409 errors do (e.g. line 3308) 🤷♂️ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typos and incorrect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not be 409. EDIT: I know we did it all over the place already, but it would be really nice to improve the situation, at least for the new errors... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use http status codes here, and 4xx are client errors, with 409 being conflict which seems correct. |
||
return | ||
} | ||
} | ||
|
||
// If we have the max number of requests already pending try to expire. | ||
if o.waiting.isFull() { | ||
// Try to expire some of the requests. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a one way check.
If consumer metadata on the server has key-pairs that are not present on the metadata passed in request, the check will still return true, a false positive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a false positive, that's the behavior I want:
I pass you a collection of metadata key/values and I want to make sure those are present in the consumer's metadata and they match the value. It's not a 'deep equal' but a 'check that those keys and values are there and the same'.