Previously, the library attempted to synchronize access to the storage across browsers and tabs using a global lock initiated by the _useSession function. Because some recursive calls (i.e. _useSession called within _useSession) were likely, the concept of a stack guard was implemented to detect such calls. This prevented deadlocks with recursion. However, stack guards appear to be quite flaky depending on the environment in which the library runs (not supported in WebKit based platforms) or transpilation/compilation/minifaction toolchains.
To go around these issues, a different approach is attempted here:
To get rid of internally recursive locks, _acquireLock is now only called at the boundary between an "external" call into GoTrueClient (all public methods essentially). All "internal" method calls, assume that a lock has been acquired correctly for them to be called.
This means that if the method is private/protected and its name starts with an underscore (_), then that method must not acquire a lock -- it is internal. Put plainly, that method should never call a public method i.e. one that does not start with an underscore. This is going to be somewhat hard to keep track of, but in v3 we'll take special care to make this easy and not rely on discipline.
All of the public signInX and MFA methods are exempt from locking, as it's assumed that they are unlikely to be used concurrently, given they rely on user interaction.
All of the other public methods that do not have a private/protected underscored variant are given one. In the public version, first they will wait for async initialization of the client to complete, before acquiring a lock which calls the underscored variant.
Async initialization of the client (which is necessary when the session stored in local storage needs to be refreshed, or when using the implicit flow to fetch the user of the session that is not encoded in the URL, or when using PKCE to exchange the code for the session) now first acquires a lock. All public methods now first wait on client initialization, instead of the library relying on it internally. It won't be possible to accidentally use an uninitialized client.
Some external concurrency is supported though. For example, if you wish to call getUser or getSession from within an onAuthStateChange callback, the client will detect that it is in an acquired lock and allow serial access to each of those calls. However, the original call will further wait for all of them to complete. Some induced dead-lock scenarios are somewhat possible, but unlikely to occur in real life.
Auto refresh ticks are considered external, however they use a try-lock, as they're repeatable. When they run, if the lock is already taken, they will just skip the refresh until the next tick.
Previously, the library attempted to synchronize access to the storage across browsers and tabs using a global lock initiated by the _useSession function. Because some recursive calls (i.e.
_useSession
called within_useSession
) were likely, the concept of a stack guard was implemented to detect such calls. This prevented deadlocks with recursion. However, stack guards appear to be quite flaky depending on the environment in which the library runs (not supported in WebKit based platforms) or transpilation/compilation/minifaction toolchains.To go around these issues, a different approach is attempted here:
_acquireLock
is now only called at the boundary between an "external" call into GoTrueClient (all public methods essentially). All "internal" method calls, assume that a lock has been acquired correctly for them to be called._
), then that method must not acquire a lock -- it is internal. Put plainly, that method should never call a public method i.e. one that does not start with an underscore. This is going to be somewhat hard to keep track of, but in v3 we'll take special care to make this easy and not rely on discipline.signInX
and MFA methods are exempt from locking, as it's assumed that they are unlikely to be used concurrently, given they rely on user interaction.getUser
orgetSession
from within anonAuthStateChange
callback, the client will detect that it is in an acquired lock and allow serial access to each of those calls. However, the original call will further wait for all of them to complete. Some induced dead-lock scenarios are somewhat possible, but unlikely to occur in real life.