Skip to content
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

[ADDED] Support for multiple subject filters on consumers #1214

Merged
merged 5 commits into from
Jun 14, 2023

Conversation

piotrpio
Copy link
Collaborator

@piotrpio piotrpio requested a review from Jarema February 20, 2023 10:28
@coveralls
Copy link

coveralls commented Feb 20, 2023

Coverage Status

Coverage: 85.359% (+0.03%) from 85.33% when pulling 9859354 on multiple-filter-subjects into 5931be0 on 2.10.0.

@piotrpio piotrpio marked this pull request as draft February 20, 2023 10:39
@piotrpio piotrpio marked this pull request as ready for review February 20, 2023 11:04
@piotrpio piotrpio changed the base branch from main to 2.10.0 February 24, 2023 14:15
@@ -408,6 +412,11 @@ func (js *js) upsertConsumer(stream, consumerName string, cfg *ConsumerConfig, o
}
return nil, info.Error
}

// check whether multiple filter subjects (if used) are reflected in the returned ConsumerInfo
if len(cfg.FilterSubjects) != 0 && len(info.Config.FilterSubjects) == 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To test this I guess would need to run against a version of the server that does not support filter subjects 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, this is basically server compatibility check.


// check whether multiple filter subjects (if used) are reflected in the returned ConsumerInfo
if len(cfg.FilterSubjects) != 0 && len(info.Config.FilterSubjects) == 0 {
return nil, ErrConsumerMultipleFilterSubjectsNotSupported
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point I think it would have have created the consumer but instead returning an error? Wondering how we should we handle creating durable consumers unintentionally that are not used, or document in the error that may have to cleanup the consumer that got created (or return both consumer info and error?).

Copy link
Collaborator Author

@piotrpio piotrpio Feb 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we were wondering how to best handle this scenario, IMO it's better to document + return an error than to fail silently and create the consumer with invalid state. I will expand on the error documentation.

test/js_test.go Outdated
js.Publish("baz", []byte("msg"))
}

sub, err := js.SubscribeSync("", nats.BindStream("TEST"), nats.ConsumerFilterSubjects("foo", "baz"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this an ephemeral consumer? do we need another one with a durable name to cover some of the conditions above?

Copy link
Member

@Jarema Jarema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, with some small nits.

@@ -375,9 +375,13 @@ func (js *js) upsertConsumer(stream, consumerName string, cfg *ConsumerConfig, o
ccSubj = fmt.Sprintf(apiLegacyConsumerCreateT, stream)
} else if err := checkConsumerName(consumerName); err != nil {
return nil, err
} else if !js.nc.serverMinVersion(2, 9, 0) || (cfg.Durable != "" && js.opts.featureFlags.useDurableConsumerCreate) {
} else if !js.nc.serverMinVersion(2, 9, 0) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else if !js.nc.serverMinVersion(2, 9, 0) ||
} else if !js.nc.serverMinVersion(2, 10, 0) ||

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check should be for 2.9.0 as it's about verifying if we can use subject with filter subject token when creating consumer (which was 2.9.0)

jsm.go Outdated Show resolved Hide resolved
Copy link
Member

@Jarema Jarema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@piotrpio piotrpio merged commit 4eac72b into 2.10.0 Jun 14, 2023
2 checks passed
@piotrpio piotrpio deleted the multiple-filter-subjects branch June 14, 2023 07:34
@tpihl
Copy link

tpihl commented Jul 2, 2023

@piotrpio I am trying to understand where our new is heading and looking at this pr, It's something I don't get;

We have a new error if filtersubjects is empty? Why?

TLDR; I think it makes more sense to allow it to be empty, and that is an indication that the consumer should not filter the stream, should get all.

In a little more detail;

If i want to read everything in the stream, do I now have to add '>'. And is that allowed or will that be illegal since it's outside the streams defined subjects.. If it's illegal, do I need to mirrior every subject from the stream definition to get all?

The concept of filtering for me is "no filters means everything". And then filters should possibly be of both types to be able to widen the filter or narrow the filter. To mimic current and my understanding if intended behavior but with the filter-perspective instead of what i would call subset-if-subjects or only-subjects;

empty filtering -> get everything
onlySubjects(subjectwithwildcard,...) -> only msgs with subject matching provided filters
exceptSubjects(subjectswithcildcards...) -> only msgs with subject NOT matching provided filter

Collisions would be avoided by a few simple sorting-criteria so that more explicit filter-parts wins over those with wildcards.

@piotrpio
Copy link
Collaborator Author

piotrpio commented Jul 2, 2023

@tpihl The error will not be returned if you provide empty or nil slice, only if you give an empty string as an element of the slice:

  • FilterSubjects: []string{} - valid
  • FilterSubjects: nil - valid
  • FilterSubjects: []string{""} - invalid

That's a safeguard on the server, and it's treated as invalid configuration. I do not see the point of providing empty string as filter value (in slice), that looks more like unintentional behavior.

The concept of filtering for me is "no filters means everything".

You're right about this - but there is a difference between providing empty slice (no filters) and providing an empty string as filter.

@tpihl
Copy link

tpihl commented Jul 2, 2023

Okay, was just reading the client code, and didn't understand the error. Maybe something like "filtersubjects cannot contain an empty string" would have been clearer?

/T

jnmoyne pushed a commit that referenced this pull request Aug 9, 2023
Signed-off-by: Piotr Piotrowski <piotr@synadia.com>
piotrpio added a commit that referenced this pull request Aug 26, 2023
Signed-off-by: Piotr Piotrowski <piotr@synadia.com>
piotrpio added a commit that referenced this pull request Sep 1, 2023
Signed-off-by: Piotr Piotrowski <piotr@synadia.com>
piotrpio added a commit that referenced this pull request Sep 1, 2023
Signed-off-by: Piotr Piotrowski <piotr@synadia.com>
piotrpio added a commit that referenced this pull request Sep 19, 2023
Signed-off-by: Piotr Piotrowski <piotr@synadia.com>
piotrpio added a commit that referenced this pull request Sep 19, 2023
Signed-off-by: Piotr Piotrowski <piotr@synadia.com>
piotrpio added a commit that referenced this pull request Sep 20, 2023
Signed-off-by: Piotr Piotrowski <piotr@synadia.com>
@piotrpio piotrpio mentioned this pull request Sep 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants