Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced "Aggregate Handler Workflow" #935

Open
jeremydmiller opened this issue Jun 17, 2024 · 2 comments
Open

Enhanced "Aggregate Handler Workflow" #935

jeremydmiller opened this issue Jun 17, 2024 · 2 comments
Labels
marten Related to Marten integration
Milestone

Comments

@jeremydmiller
Copy link
Member

Using it with a client, and I've seen a couple wrinkles to iron out. This will require a little bit of work on the Marten side too.

  1. Sometimes, even frequently, the Aggregate isn't necessary for the "decider" function. So in this case, don't even build out the aggregate. Still enforce all the same concurrency checks, but don't bother for building out the aggregate
  2. Make damn sure you don't have to use the Aggregate at all on "create" handler methods that return an IMartenOp. Thought this was done, but still
  3. Go ahead and do the optimizations at the Marten level such that an Inline aggregate is never fetched more than once. Opt into the identity map for just that aggregate type on the session

cc @gergelyurbancsik

@jeremydmiller
Copy link
Member Author

Notes

  • Use a special signature for message handlers to start it? Works on message handlers, but maybe not so much for HTTP endpoints. Something like Start(command) that returns the events? Does an StartStream using the aggregate type.
  • For HTTP endpoints, think about this
[AggregateHandler(typeof(SomeAggregate))]
public static class SomeAggregateHandler
{
    // To start the aggregate. Would be able to follow the same rules for message signatures 
    public static Events Start(command)
    {
         // Naming convention does a new stream
    }

    // Enable Wolverine to use the workflow w/o having to first build the aggregate. 
    // There's not *always* a need to do the validation
    // Might require a Marten FetchForWriting() that doesn't do the aggregation????
    public static IEnumerable<object> Handle(command)
    {

    }

    // IF the aggregate is updated through an Inline projection, make sure you don't
    // double fetch so that the aggregate is used for the projection as well
    public static IEnumerable<object> Handle(command, aggregate)
    {

    }
}

And in HTTP endpoint world:

// TODO -- figure out a better way to do starting a stream?

// MAYBE use a custom IResult for writing the aggregate from a Start???

    

    [Transactional]
    [WolverinePost("/sidekicks/{sidekickId}/rename/{name}")]
    // If Inline, update the Sidekick object built up originally
    // If live, update the Sidekick object with new events before writing to HTTP response
    public static (Sidekick, SidekickRenamed) HandleAsync(
        Guid sidekickId, 
        string name, 
        [Aggregate("sidekickId")] Sidekick sidekick
    )
    {
        var renamed = new SidekickRenamed(sidekickId, name);
        return (sidekick, renamed);
    }

@jeremydmiller
Copy link
Member Author

This might now include a slightly easier to use version of a start stream return type:

public class StartStream : List<object>, ISideEffectAware, IMartenOp
{
    public StartStream()
    {
        StreamId = global::Marten.Schema.Identity.CombGuidIdGeneration.NewGuid();
        StreamKey = StreamId.ToString();
    }

    public static Frame BuildFrame(IChain chain, Variable variable, GenerationRules rules, IServiceContainer container)
    {
        throw new NotImplementedException();
    }

    void IMartenOp.Execute(IDocumentSession session)
    {
        // nothing, just need it for the interface
    }

    public string StreamKey { get; }
    public Guid StreamId { get; }
    public Type AggregateType { get; set; }
}

Notes

  • I think StartStream would need to take the aggregate type from the [AggregateHandler]
  • You'd have to use aggregate handler attribute to use the UpdatedAggregate return type with the [AggregateHandler]
  • If using a strong typed identifier for that aggregate type, could you return the aggregate id as another return value?
  • Also support strong typed identifiers for the aggregate types
  • I think this is going to take Marten work too, so this probably doesn't make Wolverine 3.6

@jeremydmiller jeremydmiller modified the milestones: 4.0, 3.7.0 Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
marten Related to Marten integration
Projects
None yet
Development

No branches or pull requests

1 participant