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

Akshay Sura - Partner

21 Sep 2018

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 some 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. }
  61. using System ;
  62. using System . Collections . Generic ;
  63. using System . Threading . Tasks ;
  64. using Sitecore . Commerce . Core ;
  65. using Sitecore . Commerce . Core . Commands ;
  66. using Sitecore . Framework . Pipelines ;
  67.  
  68. namespace Konabos . Minions . RunMinion . Commands
  69. {
  70. public class RunMinionNowCommand : CommerceCommand
  71. {
  72.  
  73. private readonly IRunMinionPipeline _runMinionPipeline ;
  74. private readonly GetEnvironmentCommand _getEnvironment ;
  75.  
  76. public RunMinionNowCommand ( IRunMinionPipeline runMinionPipeline , IServiceProvider serviceProvider , GetEnvironmentCommand getEnvironmentPipeline )
  77. : base ( serviceProvider )
  78. {
  79. this . _runMinionPipeline  = runMinionPipeline ;
  80. this . _getEnvironment  = getEnvironmentPipeline ;
  81. }
  82.  
  83. public virtual async Task < RunMinionNowCommand > Process ( CommerceContext commerceContext , string minionFullName , string environmentName , IList < Policy > policies )
  84. {
  85. RunMinionNowCommand runMinionNowCommand  = this ;
  86. //var result = this._runMinionPipeline.Run(new RunMinionArgument(minionFullName));
  87.  
  88. //return Task.FromResult(result.IsCompleted);
  89.  
  90. using ( CommandActivity . Start ( commerceContext , ( CommerceCommand ) runMinionNowCommand ))
  91. {
  92. if ( policies  == null )
  93. policies  = ( IList < Policy >) new List < Policy >();
  94. CommerceEnvironment commerceEnvironment  = await  this . _getEnvironment . Process ( commerceContext , environmentName ) ?? commerceContext . Environment ;
  95. CommercePipelineExecutionContextOptions pipelineContextOptions  = commerceContext . GetPipelineContextOptions ();
  96. pipelineContextOptions . CommerceContext . Environment = commerceEnvironment ;
  97. IRunMinionPipeline runMinionPipeline  = this . _runMinionPipeline ;
  98. RunMinionArgument runMinionArgument  = new RunMinionArgument ( minionFullName );
  99. runMinionArgument . Policies = policies ;
  100. CommercePipelineExecutionContextOptions executionContextOptions  = pipelineContextOptions ;
  101. int num  = await runMinionPipeline . Run ( runMinionArgument , ( IPipelineExecutionContextOptions ) executionContextOptions ) ? 1 : 0 ;
  102. }
  103. return runMinionNowCommand ;
  104.  
  105. }
  106. }
  107. }
  108. // --------------------------------------------------------------------------------------------------------------------
  109. // <copyright file="ConfigureServiceApiBlock.cs" company="Sitecore Corporation">
  110. // Copyright (c) Sitecore Corporation 1999-2017
  111. // </copyright>
  112. // --------------------------------------------------------------------------------------------------------------------
  113.  
  114. namespace Sitecore . Commerce . Plugin . Sample
  115. {
  116. using System . Threading . Tasks ;
  117.  
  118. using Microsoft . AspNetCore . OData . Builder ;
  119.  
  120. using Sitecore . Commerce . Core ;
  121. using Sitecore . Commerce . Core . Commands ;
  122. using Sitecore . Framework . Conditions ;
  123. using Sitecore . Framework . Pipelines ;
  124.  
  125. /// <summary>
  126. /// Defines a block which configures the OData model
  127. /// </summary>
  128. /// <seealso>
  129. /// <cref>
  130. /// Sitecore.Framework.Pipelines.PipelineBlock{Microsoft.AspNetCore.OData.Builder.ODataConventionModelBuilder,
  131. /// Microsoft.AspNetCore.OData.Builder.ODataConventionModelBuilder,
  132. /// Sitecore.Commerce.Core.CommercePipelineExecutionContext}
  133. /// </cref>
  134. /// </seealso>
  135. [ PipelineDisplayName ( "FeatureRunMinionConfigureServiceApiBlock" )]
  136. public class ConfigureServiceApiBlock : PipelineBlock < ODataConventionModelBuilder , ODataConventionModelBuilder , CommercePipelineExecutionContext >
  137. {
  138. /// <summary>
  139. /// The execute.
  140. /// </summary>
  141. /// <param name="modelBuilder">
  142. /// The argument.
  143. /// </param>
  144. /// <param name="context">
  145. /// The context.
  146. /// </param>
  147. /// <returns>
  148. /// The <see cref="ODataConventionModelBuilder"/>.
  149. /// </returns>
  150. public override Task < ODataConventionModelBuilder > Run ( ODataConventionModelBuilder modelBuilder , CommercePipelineExecutionContext context )
  151. {
  152. Condition . Requires ( modelBuilder ). IsNotNull ( $ "{this.Name}: The argument cannot be null." );
  153.  
  154. ActionConfiguration actionConfiguration2  = modelBuilder . Action ( "RunMinionNow" );
  155. actionConfiguration2 . Parameter <string> ( "minionFullName" );
  156. actionConfiguration2 . Parameter <string> ( "environmentName" );
  157. actionConfiguration2 . ReturnsFromEntitySet < CommerceCommand >( "Commands" );
  158.  
  159.  
  160. return Task . FromResult ( modelBuilder );
  161. }
  162. }
  163. }
  164. using System ;
  165. using Quartz ;
  166. using Sitecore . Commerce . Engine . Connect ;
  167. using Sitecore . Commerce . ServiceProxy ;
  168. using Sitecore . Diagnostics ;
  169. using Sitecron . Core . Jobs ;
  170. using Sitecron . SitecronSettings ;
  171.  
  172. namespace Feature . Konabos . Loyalty . Website . SiteCron
  173. {
  174. public class RunMinionNow : IJob //Inherit from IJob interface from Quartz
  175. {
  176. public void Execute ( IJobExecutionContext context )
  177. {
  178. try
  179. {
  180. //get job parameters
  181. JobDataMap dataMap  = context . JobDetail . JobDataMap ; //get the datamap from the Quartz job
  182. var job  = ( SitecronJob ) dataMap [ SitecronConstants . ParamNames . SitecronJob ]; //get the SitecronJob from the job definition
  183. if ( job  == null )
  184. throw new Exception ( "Unable to load SiteCron Job Definition" );
  185.  
  186. Log . Info ( string . Format ( "Executing RunMinionsNow: {0} {1}" , job . MinionFullName , job . EnvironmentName ), this );
  187.  
  188. var container  = EngineConnectUtility . GetShopsContainer ();
  189. Proxy . DoCommand ( container . RunMinionNow ( job . MinionFullName , job . EnvironmentName ));
  190. }
  191. catch ( Exception ex )
  192. {
  193. Log . Error ( "Sitecron: Commerce.RunMinionNow: ERROR something went wrong - " + ex . Message , ex , this );
  194. }
  195. }
  196. }
  197. }

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


Sign up to our newsletter

Share on social media

Akshay Sura

Akshay is a nine-time Sitecore MVP and a two-time Kontent.ai. In addition to his work as a solution architect, Akshay is also one of the founders of SUGCON North America 2015, SUGCON India 2018 & 2019, Unofficial Sitecore Training, and Sitecore Slack.

Akshay founded and continues to run the Sitecore Hackathon. As one of the founding partners of Konabos Consulting, Akshay will continue to work with clients to lead projects and mentor their existing teams.


Subscribe to newsletter