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

Breaking changes for StringSet from 2.5.43 -> 2.5.61 #2071

Closed
WeihanLi opened this issue Apr 7, 2022 · 17 comments
Closed

Breaking changes for StringSet from 2.5.43 -> 2.5.61 #2071

WeihanLi opened this issue Apr 7, 2022 · 17 comments

Comments

@WeihanLi
Copy link
Contributor

WeihanLi commented Apr 7, 2022

The following code breaks when upgrade 2.5.43 -> 2.5.61

database.StringSet(_keyName, Base, _expiresIn, When.NotExists);

Error message:

Argument 4: cannot conv
ert from 'StackExchange.Redis.When' to 'bool'

Seemed it's introduced from #2029

@WeihanLi WeihanLi changed the title Breaking changes Breaking changes for StringSet from 2.5.43 -> 2.5.61 Apr 7, 2022
@mgravell
Copy link
Collaborator

mgravell commented Apr 7, 2022

Hmmm; indeed, that will be a code-breaking (but thankfully not binary-breaking) change - we must have overlooked that one, sorry. I think we should change CommandFlags flags to CommandFlags flags = CommandFlags.None (but leave the others as-is), which would allow this previous usage to continue working. Thoughts?

@mgravell
Copy link
Collaborator

mgravell commented Apr 7, 2022

(as a workaround, you can also just add , CommandFlags.None, which should restore the old usage)

@WeihanLi
Copy link
Contributor Author

WeihanLi commented Apr 7, 2022

Hi @mgravell , thanks for your quick response.

I think maybe it's more simple to adjust the order of the parameters,

For example:

- bool StringSet(RedisKey key, RedisValue value, TimeSpan? expiry = null, When when = When.Always, CommandFlags flags = CommandFlags.None)
+ bool StringSet(RedisKey key, RedisValue value, TimeSpan? expiry = null, When when = When.Always, CommandFlags flags = CommandFlags.None, bool keepTtl = false)

Another thought is to add a new method such as StringSetAndKeepTtl(maybe a better name)

@mgravell
Copy link
Collaborator

mgravell commented Apr 7, 2022

Reordering is a binary break, and we've always tried to maintain a convention of flags as the last param.

@slorello89
Copy link
Collaborator

Probably needs several smaller overloads, with each ordered sequence of optional parameters. Then in the final version the new parameter should be just prior to the flags.

@erick2red
Copy link

This caused some pain for me today. While it works perfectly fine in my development setup in Visual Studio, when I deploy to Azure it crashes with the exception below

Method not found: 'System.Threading.Tasks.Task`1<Boolean> StackExchange.Redis.IDatabaseAsync.StringSetAsync(StackExchange.Redis.RedisKey, StackExchange.Redis.RedisValue, System.Nullable`1<System.TimeSpan>, Boolean, StackExchange.Redis.When, StackExchange.Redis.CommandFlags)'

@NickCraver
Copy link
Collaborator

@erick2red Interesting - that's backwards - looking for a new method but using an older assembly? It sounds like you're silently (or with a warning) downgrading somewhere vs. what you're compiling against.

@erick2red
Copy link

I'm compiling against the latest version, and I'm deploying a package to Azure with the binaries in it. I think what's happening is that the runtimes are different, the one in my machine versus the one in the cloud service and the method resolution is tripping there. I fixed it by adding the extra parameters to the call site and making sure it wasn't calling the method with the bool keepTtl in it. Somehow, the runtime in Azure can't find that method in the Nuget being uploaded.

@erick2red
Copy link

Interestingly enough, it doesn't happen with .NET Core 5. IT happens when running .NET Framework 4.7.2.

NickCraver added a commit that referenced this issue Apr 17, 2022
I missed an overload case being an idiot - adding the missing source break for the case in #2071.

...also fixing KeyTouch ordering while in here.

Note that adding `CommandFlags` back optional seems like a quick fix and I did try that route, but in a full test suite here it became apparent that created other ambiguous overload cases, so went this route.
@NickCraver
Copy link
Collaborator

I pushed a PR to remedy this in #2098. @mgravell good for eyes when you have a chance - I did try going with the simple CommandFlags overload but wanted to add a test suite to be sure and that revealed problems there with ambiguous overloads so...went the adding another overload route. I think this covers all possible source breaks from this.

Sorry about the break here, and thanks for the report!

NickCraver added a commit that referenced this issue Apr 19, 2022
…2109)

Repeat of #2100, for after #2071 goes in.

This does a few things globally to the interfaces:
- De-dupes `<remarks>` since evidently past the first one doesn't count/render
- Links our redis command links (and all others) so they're easily clickable!
- Moves a few types to proper class files
- In places sync/async methods are adjacent, utilizes `<inheritdoc cref="" /> to de-dupe
- ...and some other misc URL cleanup throughout.

In general: docs only change - I think we should merge this as-is to help PRs coming in, then I'll continue to iterate on docs.
NickCraver added a commit that referenced this issue Apr 26, 2022
I missed an overload case being an idiot - adding the missing source break for the case in #2071.

...also fixing KeyTouch ordering while in here.

Note that adding `CommandFlags` back optional seems like a quick fix and I did try that route, but in a full test suite here it became apparent that created other ambiguous overload cases, so went this route.
@NickCraver
Copy link
Collaborator

This is fixed for the next release (on MyGet now) in #2098 - thank you for the report! We're taken some extra steps to help ensure this doesn't happen going forward.

@erick2red
Copy link

erick2red commented Jun 20, 2022

This is happening again, in 2.6.45. It's a different method this time tho.

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        Task<bool> KeyExpireAsync(RedisKey key, TimeSpan? expiry, CommandFlags flags);

        Task<bool> KeyExpireAsync(RedisKey key, TimeSpan? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None);

This is the exception message:

Method not found: 'System.Threading.Tasks.Task`1<Boolean> StackExchange.Redis.IDatabaseAsync.KeyExpireAsync(StackExchange.Redis.RedisKey, System.Nullable`1<System.TimeSpan>, StackExchange.Redis.ExpireWhen, StackExchange.Redis.CommandFlags)'

I have more details I'll write down once in a bit, once I fix my production setup.

@NickCraver
Copy link
Collaborator

I'm very curious what your call looks like because that signature looks to be present (tried very hard not to break these). If you can relay your call pattern will look ASAP, and thanks for the report!

@erick2red
Copy link

These are the two patterns:

                    var objectKey = $"{TypesMap[type].TableName.ToLower()}.{key}";
                    var db = ConnectionManager.AccountsRedis.GetDatabase(1);

...

                    var redisTasks = new List<Task>
                    {
                        db.HashSetAsync(objectKey, hashes.ToArray()),
                        db.KeyExpireAsync(objectKey, TimeSpan.FromHours(1)),
                    };

and

            string objectKey;
            if (IsRelation)
            {
                objectKey = $"{typeof(T).Name.ToLower()}.{String.Join(".", Keys)}";
            }
            else
            {
                objectKey = $"{typeof(T).Name.ToLower()}.{Key}";
            }
...
            db.KeyExpire(objectKey, TimeSpan.FromHours(1));
...

@erick2red
Copy link

So, now what happened here was the same thing as before. For some obscure reason Azure can't seem to find either of these two

...
Task<bool> KeyExpireAsync(RedisKey key, TimeSpan? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None);
...
bool KeyExpire(RedisKey key, TimeSpan? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None)

I had to go and explicitly specify flags: CommandFlags.None to make it work.

@erick2red
Copy link

So, I found something weird. When Visual Studio deploys to Azure it deploys a zip package, so I went an unzipped the thing and found the StackExchange dll.
Interestingly enough, the version of the dll shown 2.5.61.22961 and something, despite me upgrading to 2.6.45.

Now, I went ahead and deleted all the build by product folders from under VS, basically rm -rfv bin obj ..., and after rebuild, it pulls a dll with the correct version.

I need to test now, to clear the StackExchange.Redis's good name, but, the problem is that for some reason, it only breaks in Azure, apparently, VS locally uses the correct version.

@erick2red
Copy link

And, that was the problem. I'm sorry Visual Studio was being Visual Studio.

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

No branches or pull requests

5 participants