Search code examples
c#umbraco

Optimizing Database Connection for Efficient Node Creation in Umbraco CMS


I'm working on a project using Umbraco CMS where I need to create a large number of nodes (content items) programmatically using the ContentService. However, I'm facing performance issues, as there are many database commands executed during SaveAndPublish and Delete operations. The time taken for the node creation and deletion process is becoming a significant concern.

I've tried using scopes with the IScopeProvider to batch the operations, but it didn't provide the expected performance improvement.

I'm looking for advice on how to optimize the database connection and improve the performance when creating and deleting a large number of nodes in Umbraco CMS. I would like to know if there are any best practices or alternative approaches that I can use to speed up these operations.

Specifically, I'm interested in understanding how to:

  1. Efficiently create multiple nodes using the ContentService with minimum database commands.
  2. Optimize the deletion process to avoid excessive database commands and reduce execution time.

Here's my methods(I'm giving only vital parts, if you need more, endpoints or other stuff, I will edit and add it)

 private void DeleteProducts(int count)
    {
        var productFolder = _umbracoHelper.GetNodeUnderRootByAlias(ContentTypeAlias.ProductsFolder);

        var productsNamesForDeletion = Enumerable.Range(0, count).Select(i => $"Product {i} SV");
        var products = GetProducts(productFolder.Id);
        var productsToDelete = products.Where(p => productsNamesForDeletion.Contains(p.Name));

        using var scope = _scopeProvider.CreateScope(isolationLevel: IsolationLevel.Serializable, repositoryCacheMode: RepositoryCacheMode.Default, autoComplete: true);
        
        foreach (var product in productsToDelete)
        {
            _contentService.Delete(product);
        }
        
        scope.Complete();
    }

private void CreateProducts(int count, (int productFolderId, IEnumerable<LanguageModel> languages, IContentBase productPage) setupData)
    {
        using var scope = _scopeProvider.CreateScope(autoComplete: true);
        
        Enumerable.Range(0, count)
            .ForEach(i => CreateAndPublishProduct(i, setupData));

        scope.Complete();
    }
 private void CreateAndPublishProduct(int index, (int productFolderId, IEnumerable<LanguageModel> languages, IContentBase productPage) setupData)
    {
    var product = CreateProduct(index, setupData);

    _contentService.SaveAndPublish(product);
    }

Any code examples or suggestions on improving the current implementation will be greatly appreciated. Thank you in advance for your help!


Solution

  • Umbraco recommends using the ContentService for node creation, update or deletion, so your approach is correct. To reduce the impact on your Front-end server and website, you should consider using Hangfire and running Hangfire jobs in the background to handle your content.

    Here are 5 steps to achieve this - you can find more details in my Skrift article about "Performance and Availability Improvements of Umbraco Websites with Hangfire Jobs";

    1. Create a new Hangfire db, and add a new connection string with the name hangfireDB. Install Cultiv.Hangfire Umbraco package. After the installation is complete, check that you have your Hangfire tables in your new Hangfire db and you have a new Hangfire section in Umbraco backoffice. enter image description here
    2. Create a simple job for initial tests, as described in the Cultiv.Hangfire documentation or my Skrift article. enter image description here
    3. Create your services for your content creation, deletion and update and register them by implementing Umbraco's IComposer interface. enter image description here
    4. Create your Hangfire jobs composer and jobs. enter image description here enter image description here
    5. Check your Hangfire jobs.

    Following my steps, Paul Seal created a Proof of Concept GitHub repo, which should help you further.

    https://github.com/prjseal/Hangfire-Import-Proof-Of-Concept/