Howard
Howard

Reputation: 704

uCommerce - stateless API - parallelism

We are using the uCommerce Stateless API to bulk import products into uCommerce (Umbraco), see: https://docs.ucommerce.net/ucommerce/v9.5/system-integration/bulk-import-from-third-party-systems.html

The Import is taking 12 hours to complete, which is far too slow and we need to introduce parallelism.

Our code uses the async/await pattern in a .Net Framework console app.

I create a list of type Task and then execute in parallel using await Task.WhenAll(tasks);

The Task is returned by the following method.

However, this causes an exception when the method is called for each Task:

This appears to be an underlying constraint of uCommerce/NHibernate. I’m guessing because it’s sharing a DBContext somewhere.

Q. How do we work with the uCommerce Stateless API with parallelism?

Is there a way to get independent instance of the ISessionProvider?

public async Task ProcessProductAsync(dynamic currentProduct, PimApi api)
        {
            var statelessSession = ObjectFactory.Instance.Resolve<IStatelessSessionProvider>().GetStatelessSession();

            string sku = ExpandoHelper.GetListProperty(currentProduct, DynamicConstants.ParentsId);
            string variantSku = ExpandoHelper.GetProperty(currentProduct, DynamicConstants.PrimaryId);
            
            if (string.IsNullOrEmpty(sku) || string.IsNullOrEmpty(variantSku))
                return;

            var existingProduct = await statelessSession
                .Query<Product>()
                    .FetchMany(x => x.ProductDescriptions)
                        .ThenFetchMany(x => x.ProductDescriptionProperties)
                        .ThenFetch(x => x.ProductDefinitionField)
                    .FetchMany(x => x.CategoryProductRelations)
                        .ThenFetch(x => x.Category)
                    .FetchMany(x => x.ProductPrices)
                    .FetchMany(x => x.ProductProperties)
                    .Fetch(x => x.ProductDefinition)
                        .ThenFetch(x => x.ProductDefinitionFields)
                .SingleOrDefaultAsync(x => x.VariantSku == variantSku);

Upvotes: 0

Views: 195

Answers (1)

Howard
Howard

Reputation: 704

I had a response from uCommerce Support, who provided this:

"One thing you can try is to bypass the "GetStatelessSession". Once you have the type from the container, use reflection to get the following property where the sessionfactory (that creates the stateless session) is stored, and then you can open a new stateless session again. you need to access this property: internal static ISessionFactory _factory; on this type: Ucommerce.EntitiesV2.SessionProvider"

Of course uCommerce may change the internal structure of their classes, and so the above approach is brittle; but it does work.

When you resolve the type from the IoC container, you will have a Castle Proxy that needs to be unwrapped. To do that I used this code: https://stackoverflow.com/a/55671377/1053594

Once you have the unwrapped class, you can cast it as a ISessionFactory and call OpenStatelessSession to create a new session. I do this for each Task in my list, and close the session when the method is complete.

Upvotes: 0

Related Questions