5

I'm building a Sitecore Commerce 9 plugin that connects to a Message Queue and performs SellableItems updates based on the message.

I created a method to update the SellableItem and I tested it using a new CommerceCommand called from Postman - it works fine. The problem is that when I call same method from queue Message Handler, the context seems to be different then when called from Command, and the IFindEntityPipeline can't find same Category to assign the SellableItem to.

Here is my code:
Starting the Message Queue client:

public void ConfigureServices(IServiceCollection services)
    {
        var assembly = Assembly.GetExecutingAssembly();
        services.RegisterAllPipelineBlocks(assembly);

        services.Sitecore().Pipelines(config =>
            config.ConfigurePipeline<IStartEnvironmentPipeline>(configure => {
                    configure.Add<StartQueueReceiverBlock>();
                })
        );

        services.RegisterAllCommands(assembly);

        services.AddSingleton<IReceiveClient, ReceiveClient>();
    }

The pipeline block:

    public class StartQueueReceiverBlock : PipelineBlock<CommerceEnvironment,CommerceEnvironment, CommercePipelineExecutionContext>
{
    private readonly IReceiveClient _client;

    public StartQueueReceiverBlock(IReceiveClient client)
    {
        _client = client;
    }

    public override Task<CommerceEnvironment> Run(CommerceEnvironment arg, CommercePipelineExecutionContext context)
    {
        return Task.Run<CommerceEnvironment>(() =>
            {
                if(arg.Name == "HabitatAuthoring")
                    _client.Receive(context.CommerceContext);
                return arg;
            }
        );
    }
}

The queue message handler calls my SellableItemUpsertPipeline:

        private async Task ProcessMessagesAsync(Message message, CancellationToken token)
    {            
        await _sellableItemUpsertPipeline.Run(new SellableItemUpsertArgument(message), _context.GetPipelineContextOptions()); //_context passed from StartQueueReceiverBlock 

        await queueClient.CompleteAsync(message.SystemProperties.LockToken);
    }

Here is the troublesome part:

public class SellableItemUpsertBlock : PipelineBlock<SellableItemUpsertArgument, SellableItem, CommercePipelineExecutionContext>
{
    private readonly IFindEntityPipeline _findEntityPipeline;

    public SellableItemUpsertBlock(IFindEntityPipeline findEntityPipeline)
    {
        this._findEntityPipeline = findEntityPipeline;
    }

    public override async Task<SellableItem> Run(SellableItemUpsertArgument arg, CommercePipelineExecutionContext context)
    {
        //If finds Category when called from Postman, but returns null when triggered by queue message
        var entity = await _findEntityPipeline.Run(new FindEntityArgument(typeof(Category), "Entity-Category-Habitat_Master-FeaturedProducts"), context); 

        return new SellableItem();
    }

How to retrieve same entity when triggering the pipeline from queue Message Handler?

  • Could you try to pass "_client.Receive(context);" instead of "_client.Receive(context.CommerceContext);" and then use this context here "await _sellableItemUpsertPipeline.Run(new SellableItemUpsertArgument(message), _context);" instead of "await _sellableItemUpsertPipeline.Run(new SellableItemUpsertArgument(message), _context.GetPipelineContextOptions());" GetPipelineContextOptions creates new object based on CommerceContext. – vzaverugo Jun 15 '18 at 13:17
  • it may be working via postman cause you probably pass multiple headers via Postman command that help to restore the context, but these headers are not in place when registering on IStartEnvironmentPipeline – vzaverugo Jun 15 '18 at 13:21
  • @vzaverugo I guess you are right with the headers - the question is how to set same context values, when triggering pipeline without a request? Passing CommercePipelineExecutionContext instead of CommerceContext doesn't work either. – Piotr Zaborowski Jun 15 '18 at 13:57
  • If you want to pass the same context values to IStartEnvironmentPipeline, then you need to check how this pipeline is launched from Sitecore.Commerce.Engine.Startup class. In short words it does not have much information about any context requests, but is launched with basic info from *.json configuration files. You may try to add additional information before running the IStartEnvironmentPipeline pipeline, but it does not sound like a good idea. You probably need to revisit your architecture. What's the original requirement for you? – vzaverugo Jun 15 '18 at 14:24
  • The original requirement is to get messages from the Message Queue and execute a pipeline with some parameters. I use IStartEnvironmentPipeline to wire up the queue client and get the CommerceContext. If you know a better way to do it, I'm open :) – Piotr Zaborowski Jun 18 '18 at 6:39
3

Apparently the CommerceEnvironment in the CommercePipelineExecutionContext is different than the one passed as 'arg' into the Run method of my StartQueueReceiverBlock. I'm not sure if this is expected, or is it a configuration thing.

Here is my final version of this method:

public override Task<CommerceEnvironment> Run(CommerceEnvironment arg, CommercePipelineExecutionContext context)
    {
        return Task.Run<CommerceEnvironment>(() =>
            {
                if (arg.Name == "HabitatAuthoring")
                {
                    context.CommerceContext.Environment = arg;
                    _client.Receive(context.CommerceContext);
                }
                return arg;
            }
        );
    }

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.