3

We are currently experiencing an issue in our Production environment (CD or CM in a scaled CD, CM, PRC, REP and xConnect setup) where client returns contact about 10% of the time when using the example xConnect contact creation code here.

using Sitecore.Analytics.Model;
using Sitecore.Analytics.Model.Entities;
using Sitecore.XConnect;
using Sitecore.XConnect.Client;
using Sitecore.XConnect.Collection.Model;

namespace Documentation
{
    public class TrackAnonymousContacts
    {
        public void Example()
        {
            if (Sitecore.Analytics.Tracker.Current.Contact.IsNew)
            {
                var manager = Sitecore.Configuration.Factory.CreateObject("tracking/contactManager", true) as Sitecore.Analytics.Tracking.ContactManager;

                if (manager != null)
                {
                    Sitecore.Analytics.Tracker.Current.Contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
                    manager.SaveContactToCollectionDb(Sitecore.Analytics.Tracker.Current.Contact);

                    var trackerIdentifier = new IdentifiedContactReference(Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource, Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"));

                    using (XConnectClient client = Sitecore.XConnect.Client.Configuration.SitecoreXConnectClientConfiguration.GetClient())
                    {
                        try
                        {
                            var contact = client.Get<Contact>(trackerIdentifier, new Sitecore.XConnect.ContactExpandOptions());

                            if (contact != null)
                            {
                                client.SetFacet<PersonalInformation>(contact, PersonalInformation.DefaultFacetKey, new PersonalInformation()
                                {
                                    FirstName = "Myrtle" // Replace with real input source
                                });

                                client.Submit();

                                manager.RemoveFromSession(Sitecore.Analytics.Tracker.Current.Contact.ContactId);
                                Sitecore.Analytics.Tracker.Current.Session.Contact = manager.LoadContact(Sitecore.Analytics.Tracker.Current.Contact.ContactId);
                            }
                        }
                        catch (XdbExecutionException ex)
                        {
                            // Manage conflicts / exceptions
                        }
                    }
                }
            }
        }
    }
}

We do not see this issue in any other environments and it is impacting our conversion / identification of users. We've deployed additional logging and various potential solutions eg. Retry contact creation X times, using different manager methods or first identifying the user before pushing contact facets.

It is also worth noting it's running on 9.0 Update-2 and that there are no errors in the logs for the contact creation in either Sitecore or xConnect.

Has anyone experienced this issue before?

6
  • What is the error message you receive? Feb 7, 2019 at 4:22
  • There are no error messages - that is part of the problem. I only know contact is null as I was able to add extra logging.
    – Svenkle
    Feb 7, 2019 at 5:45
  • What is your server topology? How many CD servers you have? Are they load balanced? How you share session data between them? Feb 7, 2019 at 6:04
  • Development and Production environments are configured in the example same topology / settings. Environment is running as CD,CM, PRC, REP and XConnect (AIO). Session is configured at a 20 minute expiry as InProc as we only have 1 x CD server.
    – Svenkle
    Feb 7, 2019 at 6:31
  • Add logging to see what Tracker.Current.Contact.ContactId is when you are running SaveContactToCollectionDb then see if you can find the contact with that ID in the database (check xdb_collection.ContactIdentifiers table and see if you can find the ContactId in the Identifiers column. You may have to translate the ContactId from Guid.ToString("N") to hex values first (as that is what is stored in the Identifiers column). If the contact cannot be found after having run SaveContactToCollectionDb you still won't know what's wrong, but you should have narrowed the problem down a bit :)
    – GTHvidsten
    Feb 7, 2019 at 14:03

1 Answer 1

1

Your code is expecting the contact to be in the xConnect server when you request it. And maybe because of the xConnect load/network it may not be there yet.

Sitecore.Analytics.Tracker.Current.Contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
manager.SaveContactToCollectionDb(Sitecore.Analytics.Tracker.Current.Contact);
var trackerIdentifier = new IdentifiedContactReference(Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource, Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"));

Use this code and if the Tracker.Current.Contact.IsNew force the contact to be pushed back to xConnect before you ask for it. This happens in the SaveContact() function.

// here is your tracker identifier
var trackerIdentifier = GetContactReference();


public IdentifiedContactReference GetContactReference()
{
    // get the contact id from the current contact
    var id = GetContactId();

    // if the contact is new or has no identifiers
    var anon = Tracker.Current.Contact.IsNew || Tracker.Current.Contact.Identifiers.Count == 0;

    // if the user is anon, get the xD.Tracker identifier, else get the one we found
    return anon
        ? new IdentifiedContactReference(Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource, Tracker.Current.Contact.ContactId.ToString("N"))
        : new IdentifiedContactReference(id.Source, id.Identifier);
}

public Analytics.Model.Entities.ContactIdentifier GetContactId()
{
    if (Tracker.Current?.Contact == null)
    {
        return null;
    }
    if (Tracker.Current.Contact.IsNew)
    {
        // write the contact to xConnect so we can work with it
        this.SaveContact();
    }

    return Tracker.Current.Contact.Identifiers.FirstOrDefault();
}

public void SaveContact()
{
    // we need the contract to be saved to xConnect. It is only in session now
    Tracker.Current.Contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
    this.contactManager.SaveContactToCollectionDb(Tracker.Current.Contact);
}
2
  • I'm not sure what difference there is in the code you provided as I am already checking if they are new and calling SaveContactToCollectionDb().
    – Svenkle
    Feb 8, 2019 at 5:00
  • @Svenkle you are right. I did not notice that you were already doing SaveContactToCollectionDb. You code only runs if (Sitecore.Analytics.Tracker.Current.Contact.IsNew). Could that be your issue? You don't have code to run if they are not flagged as new. Once you save them to xConnect, they are no longer new. I am always returning Tracker.Current.Contact.Identifiers.FirstOrDefault(); as the identifier. And only saving if IsNew.
    – Chris Auer
    Feb 8, 2019 at 5:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.