DistributedLock icon indicating copy to clipboard operation
DistributedLock copied to clipboard

Unable to create MySqlDistributedSynchronizationProvider by using MySqlConnection via"ProvidePasswordCallback"

Open jeyamaal opened this issue 11 months ago • 3 comments

I couldn't create MySqlDistributedSynchronizationProvider by passing MySQLConnection.

But It's working with by passing same connection string new MySqlDistributedSynchronizationProvider(connectionString)

I also tried without ProvidePasswordCallback, that is also not working.

Code:

      services.AddScoped<IDistributedLockProvider>(serviceProvider =>
        {

            var connection = new MySqlConnection(connectionString) // this is not included password
            {
                ProvidePasswordCallback = conn =>
                {
                    return accessToken;  // password 
                },
            };
            return new MySqlDistributedSynchronizationProvider(connection);
        });

Error:

System.InvalidOperationException: The connection and/or transaction are disposed or closed
   at Medallion.Threading.Internal.Data.DedicatedConnectionOrTransactionDbDistributedLock.TryAcquireAsync[TLockCookie](TimeoutValue timeout, IDbSynchronizationStrategy`1 strategy, CancellationToken cancellationToken, IDistributedSynchronizationHandle contextHandle) in /_/src/DistributedLock.Core/Internal/Data/DedicatedConnectionOrTransactionDbDistributedLock.cs:line 66
   at Medallion.Threading.Internal.Data.DedicatedConnectionOrTransactionDbDistributedLock.TryAcquireAsync[TLockCookie](TimeoutValue timeout, IDbSynchronizationStrategy`1 strategy, CancellationToken cancellationToken, IDistributedSynchronizationHandle contextHandle) in /_/src/DistributedLock.Core/Internal/Data/DedicatedConnectionOrTransactionDbDistributedLock.cs:line 94
   at Medallion.Threading.Internal.DistributedLockHelpers.Wrap[THandle](ValueTask`1 handleTask, Func`2 factory) in /_/src/DistributedLock.Core/Internal/DistributedLockHelpers.cs:line 38
   at Medallion.Threading.Internal.Helpers.Convert[TDerived,TBase](ValueTask`1 task, ValueTaskConversion _) in /_/src/DistributedLock.Core/Internal/Helpers.cs:line 22.

Versions: DistributedLock.MySql: 1.0.2 MySql server: 8.0.23 Dotnet : 8 MySqlConnector: 2.4.0

jeyamaal avatar Jan 24 '25 10:01 jeyamaal

@jeyamaal the reason to construct a lock around a particular connection instance is so that you can ensure the lock is acquired on that specific connection. Here, you're passing a closed connection. Currently, DistributedLock does not open "externally owned" connections that are passed in (I suppose we could implement "open if needed and close if opened" behavior like EntityFramework; I haven't given it much thought).

Anyway, what you're doing should work if you open the connection before attempting to acquire the lock.

I'm curious: what is your use-case for not simply using a connection string?

madelson avatar Jan 25 '25 02:01 madelson

@madelson , I need the providePasswordCallback approach, since I'm using token-based authentication with AWS RDS IAM. It helps effectively manage connection pooling, as token-based authentication creates a new connection string after a certain time period.

Refer: https://mysqlconnector.net/api/mysqlconnector/mysqlconnection/providepasswordcallback/

jeyamaal avatar Jan 25 '25 03:01 jeyamaal

Thanks for the context @jeyamaal that makes sense.

As I mentioned, the current workaround is to open the connection yourself before attempting to acquire the lock (or equivalently construct the lock/provider using an already-opened connection).

If you are interested in contributing, an option could be to add support for a constructor that uses DbDataSource. This would let you leverage the password callback via this API.

You can see this commit where someone contributed that functionality for Postgres; the actual change set is really quite simple and small.

Let me know if making such a contribution interests you; otherwise I'll put this on the backlog.

madelson avatar Jan 26 '25 21:01 madelson