I've got a site where I'm invoking Tracker.Current.Session.Identify()
, passing in the authenticated user's email address.
It works fine locally, but when deployed the identify call often - but not always - throws the following exception:
ContactLockException: The contact {guid} could not be locked in the xDB
Here's where it seems to get weird: the contact ID in the exception:
- Is not the same as
Tracker.Current.Contact.ContactId
- Changes every request, if the identify is retried
Tracker.Current.Contact.ContactId
remains the same throughout. The SC_ANALYTICS_GLOBAL_COOKIE
is also static, as is the session ID cookie.
I've checked that the Analytics.ClusterName
is correctly set in all cases.
- Sitecore 8.1 Update-1
- SQL Session (shared + private)
Has anyone experienced this before and solved it?
Edit: I know what is happening, but I don't yet know why.
Here's the scenario:
alice
visits the site, logs in, and gets aKnown
contact associated to the browser cookiebob
visits the site, on the same computer as Alice, and logs in using the same browser. Now when we identify the contact asbob
, xDB realizes that the current contact needs to be split off because it's already identified as someone else (alice
).- so xDB creates a new contact ID to put
bob
into, sets it to haveIdentifier = bob
andLevel = Known
, and then callsContactManager.FlushContactToXdb()
on it.
Good so far, right? Making sure bob
's data doesn't overwrite alice
's, even though they have been from the same browser/global analytics cookie.
The error here comes into play later in the identify process when it calls contactManager.TryLoadContact()
. This is done to get the existing contact from xDB - in this case, it's using the new contact ID it created for bob
.
TryLoadContact()
, however, is returning that the contact was not found (LockAttemptStatus = NotFound
).
TL;DR it appears that calling ContactManager.FlushContactToXdb(id)
immediately followed by contactManager.TryLoadContact(id)
is resulting in being unable to load the contact from xDB!
FWIW, Mongo is not a replica set in this case so it couldn't be that a write hadn't propagated to a replica member. Unless Mongo writes are async, which maybe they are...
Edit 2
I've verified that for some reason data is not being written to xDB. The only contacts present are those that were written as a test when I pointed my local dev instance at the shared dev mongo DBs.
I have also verified steps in https://kb.sitecore.net/articles/977445 are okay
- Checked connectivity from CM server to Mongo using robomongo
- Private and shared session are using SQL sessions
- CDN not present
Global.asax
is present and inherits from Sitecore base classSc.VisitorIdentification()
is on the layoutIgnoreUrlPrefixes
does not contain layoutsSitecore.MvcAnalytics.config
is present- Verified that enableTracking is true on the site
So data isn't being written. And worse exceptions don't seem to be getting thrown - there's nothing at all in the logs, and Sitecore seems unaware that FlushContactToXdb()
has not worked.
.TryLoadContact()
returns the status ofNotFound
? It could potentially returnAlreadyLocked
(unlikely) orDatabaseUnavailable
. Have you verified that the contacts with those IDs end up created and unlocked in MongoDB?Identify
method and ran it :)Analytics.Robots.IgnoreRobots
andAnalytics.AutoDetectBots
tofalse
in the Sitecore.Analytics.Tracking.config. If contacts are saved after this, then we'll know which part of the code is at the root of the issue.