Run Sitecore Commerce (XC) 9 Minion using Sitecore Precision Scheduling with SiteCron in powerful ways!

In this video I am going to walk you through how to use the SiteCron module to run Sitecore Commerce Engine Minions. Sitecore jobs along with Sitecore Commerce Minions run on an interval basis. If you need a way to accurately run your Minions based on CRON expressions or at a specific date and time, you would need to use SiteCron. Here is come code:

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Threading.Tasks;
    4. using System.Web.Http.OData;
    5. using Konabos.Minions.RunMinion.Commands;
    6. using Microsoft.AspNetCore.Mvc;
    7. using Newtonsoft.Json.Linq;
    8. using Sitecore.Commerce.Core;
    9. using Sitecore.Commerce.Core.Commands;
    10.  
    11. namespace Konabos.Minions.RunMinion.Controllers
    12. {
    13. public class CommandsController : CommerceController
    14. {
    15. private readonly EntitySerializerCommand _entitySerializerCommand;
    16.  
    17. public CommandsController(IServiceProvider serviceProvider, CommerceEnvironment globalEnvironment, EntitySerializerCommand entitySerializerCommand)
    18. : base(serviceProvider, globalEnvironment)
    19. {
    20. this._entitySerializerCommand = entitySerializerCommand;
    21. }
    22.  
    23.  
    24. [HttpPut]
    25. [Route("RunMinionNow()")]
    26. public async Task<IActionResult> RunMinionNow([FromBody] ODataActionParameters value)
    27. {
    28. CommandsController commandsController = this;
    29. if (!commandsController.ModelState.IsValid || value == null)
    30. return (IActionResult)new BadRequestObjectResult(commandsController.ModelState);
    31. if (value.ContainsKey("minionFullName") && value.ContainsKey("environmentName"))
    32. {
    33. var minionFullName = value["minionFullName"].ToString();
    34. var environmentName = value["environmentName"].ToString();
    35. if ((!string.IsNullOrEmpty(minionFullName != null ? minionFullName.ToString() : (string)null)) && (!string.IsNullOrEmpty(environmentName != null ? environmentName.ToString() : (string)null)))
    36. {
    37.  
    38. List<Policy> policies = new List<Policy>();
    39. if (value.ContainsKey("policies"))
    40. {
    41. JArray jarray = (JArray)value["policies"];
    42. if (jarray != null)
    43. {
    44. foreach (object obj in jarray)
    45. {
    46. string serializedEntity = obj.ToString().Replace(""@odata.type": "#Sitecore.Commerce.Core.RunMinionPolicy"", ""$type": "Sitecore.Commerce.Core.RunMinionPolicy, Sitecore.Commerce.Core"");
    47. policies.Add(await commandsController._entitySerializerCommand.Deserialize<Policy>(commandsController.CurrentContext, serializedEntity));
    48. }
    49. }
    50. }
    51.  
    52. RunMinionNowCommand command = commandsController.Command<RunMinionNowCommand>();
    53. var resutlt = await command.Process(commandsController.CurrentContext, minionFullName, environmentName, policies);
    54. return (IActionResult)new ObjectResult((object)command);
    55. }
    56. }
    57. return (IActionResult)new BadRequestObjectResult((object)value);
    58. }
    59. }
    60. }

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Threading.Tasks;
    4. using Sitecore.Commerce.Core;
    5. using Sitecore.Commerce.Core.Commands;
    6. using Sitecore.Framework.Pipelines;
    7.  
    8. namespace Konabos.Minions.RunMinion.Commands
    9. {
    10. public class RunMinionNowCommand : CommerceCommand
    11. {
    12.  
    13. private readonly IRunMinionPipeline _runMinionPipeline;
    14. private readonly GetEnvironmentCommand _getEnvironment;
    15.  
    16. public RunMinionNowCommand(IRunMinionPipeline runMinionPipeline, IServiceProvider serviceProvider, GetEnvironmentCommand getEnvironmentPipeline)
    17. : base(serviceProvider)
    18. {
    19. this._runMinionPipeline = runMinionPipeline;
    20. this._getEnvironment = getEnvironmentPipeline;
    21. }
    22.  
    23. public virtual async Task<RunMinionNowCommand> Process(CommerceContext commerceContext, string minionFullName, string environmentName, IList<Policy> policies)
    24. {
    25. RunMinionNowCommand runMinionNowCommand = this;
    26. //var result = this._runMinionPipeline.Run(new RunMinionArgument(minionFullName));
    27.  
    28. //return Task.FromResult(result.IsCompleted);
    29.  
    30. using (CommandActivity.Start(commerceContext, (CommerceCommand)runMinionNowCommand))
    31. {
    32. if (policies == null)
    33. policies = (IList<Policy>)new List<Policy>();
    34. CommerceEnvironment commerceEnvironment = await this._getEnvironment.Process(commerceContext, environmentName) ?? commerceContext.Environment;
    35. CommercePipelineExecutionContextOptions pipelineContextOptions = commerceContext.GetPipelineContextOptions();
    36. pipelineContextOptions.CommerceContext.Environment = commerceEnvironment;
    37. IRunMinionPipeline runMinionPipeline = this._runMinionPipeline;
    38. RunMinionArgument runMinionArgument = new RunMinionArgument(minionFullName);
    39. runMinionArgument.Policies = policies;
    40. CommercePipelineExecutionContextOptions executionContextOptions = pipelineContextOptions;
    41. int num = await runMinionPipeline.Run(runMinionArgument, (IPipelineExecutionContextOptions)executionContextOptions) ? 1 : 0;
    42. }
    43. return runMinionNowCommand;
    44.  
    45. }
    46. }
    47. }

    1. // --------------------------------------------------------------------------------------------------------------------
    2. // <copyright file="ConfigureServiceApiBlock.cs" company="Sitecore Corporation">
    3. // Copyright (c) Sitecore Corporation 1999-2017
    4. // </copyright>
    5. // --------------------------------------------------------------------------------------------------------------------
    6.  
    7. namespace Sitecore.Commerce.Plugin.Sample
    8. {
    9. using System.Threading.Tasks;
    10.  
    11. using Microsoft.AspNetCore.OData.Builder;
    12.  
    13. using Sitecore.Commerce.Core;
    14. using Sitecore.Commerce.Core.Commands;
    15. using Sitecore.Framework.Conditions;
    16. using Sitecore.Framework.Pipelines;
    17.  
    18. /// <summary>
    19. /// Defines a block which configures the OData model
    20. /// </summary>
    21. /// <seealso>
    22. /// <cref>
    23. /// Sitecore.Framework.Pipelines.PipelineBlock{Microsoft.AspNetCore.OData.Builder.ODataConventionModelBuilder,
    24. /// Microsoft.AspNetCore.OData.Builder.ODataConventionModelBuilder,
    25. /// Sitecore.Commerce.Core.CommercePipelineExecutionContext}
    26. /// </cref>
    27. /// </seealso>
    28. [PipelineDisplayName("FeatureRunMinionConfigureServiceApiBlock")]
    29. public class ConfigureServiceApiBlock : PipelineBlock<ODataConventionModelBuilder, ODataConventionModelBuilder, CommercePipelineExecutionContext>
    30. {
    31. /// <summary>
    32. /// The execute.
    33. /// </summary>
    34. /// <param name="modelBuilder">
    35. /// The argument.
    36. /// </param>
    37. /// <param name="context">
    38. /// The context.
    39. /// </param>
    40. /// <returns>
    41. /// The <see cref="ODataConventionModelBuilder"/>.
    42. /// </returns>
    43. public override Task<ODataConventionModelBuilder> Run(ODataConventionModelBuilder modelBuilder, CommercePipelineExecutionContext context)
    44. {
    45. Condition.Requires(modelBuilder).IsNotNull($"{this.Name}: The argument cannot be null.");
    46.  
    47. ActionConfiguration actionConfiguration2 = modelBuilder.Action("RunMinionNow");
    48. actionConfiguration2.Parameter<string>("minionFullName");
    49. actionConfiguration2.Parameter<string>("environmentName");
    50. actionConfiguration2.ReturnsFromEntitySet<CommerceCommand>("Commands");
    51.  
    52.  
    53. return Task.FromResult(modelBuilder);
    54. }
    55. }
    56. }

    1. using System;
    2. using Quartz;
    3. using Sitecore.Commerce.Engine.Connect;
    4. using Sitecore.Commerce.ServiceProxy;
    5. using Sitecore.Diagnostics;
    6. using Sitecron.Core.Jobs;
    7. using Sitecron.SitecronSettings;
    8.  
    9. namespace Feature.Konabos.Loyalty.Website.SiteCron
    10. {
    11. public class RunMinionNow : IJob //Inherit from IJob interface from Quartz
    12. {
    13. public void Execute(IJobExecutionContext context)
    14. {
    15. try
    16. {
    17. //get job parameters
    18. JobDataMap dataMap = context.JobDetail.JobDataMap; //get the datamap from the Quartz job
    19. var job = (SitecronJob)dataMap[SitecronConstants.ParamNames.SitecronJob]; //get the SitecronJob from the job definition
    20. if (job == null)
    21. throw new Exception("Unable to load SiteCron Job Definition");
    22.  
    23. Log.Info(string.Format("Executing RunMinionsNow: {0} {1}", job.MinionFullName, job.EnvironmentName), this);
    24.  
    25. var container = EngineConnectUtility.GetShopsContainer();
    26. Proxy.DoCommand(container.RunMinionNow(job.MinionFullName, job.EnvironmentName));
    27. }
    28. catch (Exception ex)
    29. {
    30. Log.Error("Sitecron: Commerce.RunMinionNow: ERROR something went wrong - " + ex.Message, ex, this);
    31. }
    32. }
    33. }
    34. }

If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).

Links:
*https://www.akshaysura.com/?s=sitecron
*https://github.com/akshaysura/Sitecron