Fix UniqueOpts.ExcludeKind being silently ignored by isEmpty() - #1404
Conversation
6fb21b7 to
e797f26
Compare
|
@JackDanger Thanks!! Could you sign the CLA please? A small bug in the new validation is that this shape of UniqueOpts{
ExcludeKind: true,
ByState: rivertype.UniqueOptsByStateDefault(),
}We could modify your logic to also allow UniqueOpts{ExcludeKind: true}I wonder if maybe what we should do here is keep the |
e797f26 to
6eeeb85
Compare
|
Thanks Jack! @bgentry Can I get your opinion on this one as well? I suggested to Jack that we drop validation in favor of allowing |
|
signed! riverqueue/rivercla#36 I'm looking for ways to make this a little more elegant and I appreciate the review and feedback 🙇 |
|
@JackDanger Thanks :) Ugh, I hate to do this, but I was thinking about this more tonight, and I think what you had originally was probably better. Allowing What do you think about resurrecting a validation like this? if o.ExcludeKind && !o.ByArgs && !o.ByQueue && o.ByPeriod == 0 {
return errors.New("UniqueOpts.ExcludeKind requires ByArgs, ByQueue, or ByPeriod")
}And in case we ever get a complaint about it, we could reevaluate. Sorry about the flip flop :/ I should have thought harder about this when I suggested the original change. |
The public UniqueOpts.isEmpty() does not consider ExcludeKind, against the warning in its own doc comment, while dbunique.UniqueOpts.IsEmpty() in internal/dbunique does. A UniqueOpts with only ExcludeKind set is therefore treated as unset by insertParamsFromConfigArgsAndOptions, and uniqueness silently never applies. - TestUniqueOpts_isEmpty now asserts both isEmpty implementations agree for every field permutation. - TestUniqueOpts_validateExcludeKind asserts an ExcludeKind-only config is rejected (the resulting key would be constant across the whole table). - Two subtests in TestInsertParamsFromJobArgsAndOptions cover rejection via the real insert-params path and key equality across kinds with ByArgs+ExcludeKind. These tests fail until the isEmpty()/validate() fix lands.
The public UniqueOpts.isEmpty() never considered ExcludeKind — against the explicit warning in its own doc comment — even though d977e10 added the field alongside the same option inside internal/dbunique, whose IsEmpty() does consider it. Callers passing only UniqueOpts{ExcludeKind: true} therefore had no unique key computed at all: jobs were inserted with no dedup, silently, while the option's doc promised uniqueness "across all jobs regardless of kind". - isEmpty() now counts ExcludeKind, matching dbunique.UniqueOpts.IsEmpty(). - validate() rejects the ExcludeKind-only combination: the unique key is built from kind/args/queue/period, so kind excluded and nothing else included leaves no key to dedupe by. The combination is safe to re-evaluate if a justified use shows up, per review. - The UniqueOpts.ExcludeKind doc comment states the combination requirement. Signed-off-by: Jack Danger <github@jackcanty.com>
6eeeb85 to
8e3ef79
Compare
|
Thanks Brandur, addressed in 8e3ef79 |
The patch in #1404 contains a minor breaking change in which using `UniqueOpts{ExcludeKind: true}` with no other options now returns an error, and we'd put in a breaking change banner right at the top of the release. This is a breaking change, but it's quite a minor one, and one that I don't think is likely to affect many users, if anybody. If it does affect someone, it's the "good" kind of breaking change in that it returns an error immediately instead of having some new unintended side effect. I don't think this quite meets the bar for a call out right at the top of the release, so here I'm demoting it so that we mention the breaking change, but inline with the changelog entry for #1404 instead.
UniqueOpts.ExcludeKindis silently ignored on master. The publicisEmpty()never looks at it — despite its own doc comment warning that every new option must be added there — while the copy of the same opts ininternal/dbunique(dbunique.UniqueOpts.IsEmpty()) does count it. SoUniqueOpts{ExcludeKind: true}inserts jobs with no unique key at all, and when a worker also carries unique opts, those silently override the caller's instead.Two commits: first the failing test (
TestUniqueOpts_isEmptyasserts the public and internalisEmptyagree for every field combination), then the fix — just theisEmpty()one-liner. Acceptance tests pin the insert-params path around it.After review, the corner config
{ExcludeKind: true}with nothing else set stays valid: it now applies uniqueness across all jobs (a whole-table key, sinceByStatedefaults toUniqueOptsByStateDefault()when unset) instead of being silently ignored.Reproduce on master with just the test commit:
(the acceptance tests in the branch stay green on master too — the twin-parity assertion is the one that fails.)