Mario,
I'm not sure if I am reading your article correctly. It looks like all of your command handlers would be triggered for every change feed event even when they did not have processing logic for that given command. You write about having logic to basically ignore those commands so that they are correctly processed by the correct command handler.
Is there a more efficient way to do this? Is there some way to filter the change feed so that the function is not triggered unless the correct set of subscribed commands came through? Or, instead of using cosmos DB, could the API function send the command directly to Event Grid ?
There isn't a current way to filter documents with the Change Feed trigger for Azure Functions. I'll try to find the GitHub issue, but this looks like the tracking request is here: feedback.azure.com/forums/263030-a...
I've done this manually by implementing an interface (e.g. ICommandProcessor) with 2 methods: Handle & CanHandle. The command handler function, that's processing all commands, injects all handlers (IEnumerable ICommandProcessor ) and filters processing of each command based off the CanHandle method. I've implemented CanHandle both with reflection and direct lists of types. Reflection strategy grabs all parameters of methods named HandleAsync which implement ICommand to check against. Though, I don't like the idea of using reflection in Azure functions due to cold starts.
EDIT: Was on mobile previously, adding context
Here's an example (incomplete and probably has issues) of the command handler strategy based on Mario's post:
public class ExampleCommandProcessor : ICommandProcessor
{
private readonly IEventStoreLogic _eventStore;
private static readonly IEnumerable<Type> HandledCommands = typeof(ExampleCommandProcessor)
.GetMethods(BindingFlags.Instance)
.SelectMany(x => x.GetParameters()
.Where(p => typeof(ICommand).IsAssignableFrom(p.ParameterType))
.Select(t => t.ParameterType));
public ExampleCommandProcessor(IEventStoreLogic eventStore)
{
_eventStore = eventStore;
}
public bool CanHandle(ICommand command)
{
return HandledCommands.Contains(command.GetType());
}
public Task HandleAsync(ICommand command, IAsyncCollector<Event> azureOutputBinding = null)
{
return HandleCommand((dynamic)command, azureOutputBinding);
}
private async Task HandleCommand(CreateItem command,
IAsyncCollector<Event> azureOutputBinding = null)
{
if (azureOutputBinding != null) _eventStore.SetWritePersistence(azureOutputBinding);
var itemStream = await _eventStore.LoadAggregateStreamAsync(command.AggregateId);
if (itemStream .Any()) throw new SomeRandomException();
var newItem = Item.AddOrSomething(command); // static in this example
await UpdateStream(newItem);
}
... continue multiple handlers with concrete commands
If you need more guidance on it, I'd look at in-process messaging platform strategies, like Mediatr or MassTransit's Mediator. They perform a lot of black box magic behind the scenes, that have a similar concept.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Mario,
I'm not sure if I am reading your article correctly. It looks like all of your command handlers would be triggered for every change feed event even when they did not have processing logic for that given command. You write about having logic to basically ignore those commands so that they are correctly processed by the correct command handler.
Is there a more efficient way to do this? Is there some way to filter the change feed so that the function is not triggered unless the correct set of subscribed commands came through? Or, instead of using cosmos DB, could the API function send the command directly to Event Grid ?
There isn't a current way to filter documents with the Change Feed trigger for Azure Functions. I'll try to find the GitHub issue, but this looks like the tracking request is here:
feedback.azure.com/forums/263030-a...
I've done this manually by implementing an interface (e.g. ICommandProcessor) with 2 methods: Handle & CanHandle. The command handler function, that's processing all commands, injects all handlers (IEnumerable ICommandProcessor ) and filters processing of each command based off the CanHandle method. I've implemented CanHandle both with reflection and direct lists of types. Reflection strategy grabs all parameters of methods named HandleAsync which implement ICommand to check against. Though, I don't like the idea of using reflection in Azure functions due to cold starts.
EDIT: Was on mobile previously, adding context
Here's an example (incomplete and probably has issues) of the command handler strategy based on Mario's post:
If you need more guidance on it, I'd look at in-process messaging platform strategies, like Mediatr or MassTransit's Mediator. They perform a lot of black box magic behind the scenes, that have a similar concept.