5

I noticed the call to update the customer details onto xDB is taking considerable amount of time so I would like to do it in a separate thread so that application does not have to wait until the update finish. So tried Task.Run() but If I use this Tracker.Current.Session.Identify(custId) is always null.

Any inputs on how I approach this?

7
  • Is it possible to update the contact in xdb on session end? Apr 9 '18 at 5:17
  • I want to do it when a customer logs in Apr 9 '18 at 6:23
  • Can you share the code snippet on how you are fetching the contact and updating it? Apr 9 '18 at 9:14
  • Which version of Sitecore are you on? Sitecore 9 has async calls to xConnect... Apr 9 '18 at 13:14
  • We are on sitecore 8.2 Apr 10 '18 at 0:44
3

For clarity to the reader: the following answer and code snippets are for Sitecore 8.2.X only and will not work for Sitecore 9.X.

We got in contact with Sitecore Support who confirmed that it isn't supported for separate threads using their API. We were able to get something working by using a workaround. This hasn't had full code tidy up done yet - just a PoC.

We are able to run this using Task.Run successfully and have data pushed to XDB. It also handles DB locking scenarios if that is of interest, otherwise, you can ignore it.

namespace Sample.Foundation.Accounts.Respositories
{
  [Service(typeof(IUpdateAnalyticsRepository))]
  public class UpdateAnalyticsRepository: IUpdateAnalyticsRepository
  {
    private ContactManager _manager = Sitecore.Configuration.Factory.CreateObject("tracking/contactManager", true) as ContactManager;
    private ContactRepository _repository = Sitecore.Configuration.Factory.CreateObject("tracking/contactRepository", true) as ContactRepository;

    public ContactManager XdbContactManager
    {
        get { return _manager; }
    }

    public ContactRepository XdbContactRepository
    {
        get { return _repository; }
    }

    public Contact GetXdbContact(string identifier)
    {
        var contact = XdbContactRepository.LoadContactReadOnly(identifier);

        if (contact != null) return contact;

        var leaseOwner = new LeaseOwner(GetType() + Guid.NewGuid().ToString(), LeaseOwnerType.OutOfRequestWorker);

        contact = XdbContactRepository.CreateContact(Guid.NewGuid());

        if (contact == null) return null;

        contact.Identifiers.Identifier = identifier;

        //Setting these values allows processing and aggregation to process this contact without erroring.
        contact.System.Value = 0;
        contact.System.VisitCount = 0;

        //MAKE OTHER Contact Changes here too if you need to on Create.

        XdbContactRepository.SaveContact(contact, new ContactSaveOptions(true, leaseOwner));

        return contact;
    }

    public void UpdateXdbContact(string identifier, string firstName, string lastName, string email)
    {

        try
        {
            var currentContact = GetXdbContact(identifier);

            if (currentContact == null)
                return;

            var lockResult = XdbContactManager.TryLoadContact(currentContact.ContactId);

            Contact updatedContact = currentContact;

            switch (lockResult.Status)
            {
                case LockAttemptStatus.Success:
                    var lockedContact = lockResult.Object;
                    lockedContact.ContactSaveMode = ContactSaveMode.AlwaysSave;
                    updatedContact = UpdateContactInfo(lockedContact, firstName, lastName, email, identifier);  //this method should do work on lockedContact and return lockedContact.  this then saves it as updatedContact.
                    break;
                case LockAttemptStatus.NotFound:
                    updatedContact = currentContact;
                    break;
                default:
                    var exception = new Exception(GetType() + " Contact could not be locked - " + currentContact.ContactId);
                    Sitecore.Diagnostics.Log.Error(string.Format("[{1}:SaveContactInfoToXdb] Can't Lock or Find xDB Contact {0}", currentContact.ContactId, GetType()), exception);
                    break;
            }

            //Save Contact Information - This is the ContactManager method to use
            XdbContactManager.SaveAndReleaseContact(updatedContact);

        }
        catch (Exception exception)
        {
            Sitecore.Diagnostics.Log.Error($"Error in updating contact identifier {identifier}", exception);
        }


    }

    private Contact UpdateContactInfo(Contact lockedContact, string firstName, string lastName, string customerId, string email)
    {
        try
        {
            var personalInfo = lockedContact.GetFacet<IContactPersonalInfo>("Personal");

            personalInfo.FirstName = firstName;
            personalInfo.Surname = lastName;


            var contactEmails = lockedContact.GetFacet<IContactEmailAddresses>("Emails");

            if (contactEmails != null)
            {
                IEmailAddress contactEmail = null;

                if (contactEmails.Entries.Contains("Personal Email"))
                {
                    contactEmail = contactEmails.Entries["Personal Email"];
                }
                else
                {
                    contactEmail = contactEmails.Entries.Create("Personal Email");
                    contactEmails.Preferred = "Personal Email";
                }
                contactEmail.SmtpAddress = email;
            }
        }
        catch (Exception exception)
        {
            Sitecore.Diagnostics.Log.Error($"Error in updating contact identifier {lockedContact.Identifiers.Identifier}", exception);
            return null;
        }
        return lockedContact;
    }
}

}

This can then be called wrapped in a Try-Catch to ensure no impacts to other functionality should something go wrong (Personalisation is a "Nice to have" not a "Must Have" right?) and run using something like this:

try
{
   //fire update xDB event in the background but don't wait for it to complete and don't worry about if it succeeds or not (personalization is "nice to have" only).
  Task.Run(() => _updateAnalyticsRepositoryClient.UpdateXdbContact(customerOrderModel.Customer.CustomerId, customerOrderModel.Customer.FirstName, customerOrderModel.Customer.LastName, customerOrderModel.Customer.Email));
   }
   catch (Exception ex)
   {
      _logManagerClient.Warn(string.Format("Error updating XDB data for customer {0}. Exception was: {1}", customerId, ex));
      throw;
   }

Excuse the PoC code but give that a go and see what you think :)

1
  • 1
    I hope you don't mind, I added the blockquote at the top to make it clear this is for Sitecore 8.2 only. May 3 '18 at 13:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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