getSession() is problematic. The issue comes because whenever the library itself does anything with the session, it may be very quick < 10ms or very slow >= 10s. For example, if a session needs to be refreshed, when you call getSession() the response may be very quick or take very long.
When such long processing is required, a race condition arises between multiple windows or tabs concurrently doing the same processing. In reality, only one such tab / window (in further text "process") needs to do the processing. Therefore, just using a concept like a method call to getSession() is not advisable.
With this change, the internals of the library use a new function called _useSession() which expects a callback to be provided. So long as the callback's promise has not resolved, the session is "being used." In follow up PRs, locking semantics will be used to ensure that only one _useSession callback is active amongst all processes.
The existing getSession() computation is put behind __loadSession which should not be used outside of _useSession(). A debug-mode stack check is performed to make sure that issues like that are caught.
This PR also adds two new utility functions stackGuard and isInStackGuard. These can be used to detect recursive calls or inappropriate use of methods. For example, in this PR a stack guard is used at debug time to make sure that __loadSession is only called within _useSession, as that is the only valid use of the method. In follow up versions this will become a runtime exception.
It works because when using async/await JS engines like browsers and Node will respect stack traces. A stack guard is a special string that shows up in the stack trace of the Error object, which if seen (by isInStackGuard) can be used to detect whether a function was called from the correct parent-caller or whether there is a recursive call.
It's not possible to use plain functions because of JS minification, which mangles the name of virtually all functions, so a trick has to be used to dynamically generate a function name which is the special stack guard string.
getSession()
is problematic. The issue comes because whenever the library itself does anything with the session, it may be very quick < 10ms or very slow >= 10s. For example, if a session needs to be refreshed, when you callgetSession()
the response may be very quick or take very long.When such long processing is required, a race condition arises between multiple windows or tabs concurrently doing the same processing. In reality, only one such tab / window (in further text "process") needs to do the processing. Therefore, just using a concept like a method call to
getSession()
is not advisable.With this change, the internals of the library use a new function called
_useSession()
which expects a callback to be provided. So long as the callback's promise has not resolved, the session is "being used." In follow up PRs, locking semantics will be used to ensure that only one_useSession
callback is active amongst all processes.The existing
getSession()
computation is put behind__loadSession
which should not be used outside of_useSession()
. A debug-mode stack check is performed to make sure that issues like that are caught.This PR also adds two new utility functions
stackGuard
andisInStackGuard
. These can be used to detect recursive calls or inappropriate use of methods. For example, in this PR a stack guard is used at debug time to make sure that__loadSession
is only called within_useSession
, as that is the only valid use of the method. In follow up versions this will become a runtime exception.It works because when using async/await JS engines like browsers and Node will respect stack traces. A stack guard is a special string that shows up in the stack trace of the
Error
object, which if seen (byisInStackGuard
) can be used to detect whether a function was called from the correct parent-caller or whether there is a recursive call.It's not possible to use plain functions because of JS minification, which mangles the name of virtually all functions, so a trick has to be used to dynamically generate a function name which is the special stack guard string.