Comments (10)
Also another area of interest for us as I too have written code to support something called a 'Saga' which wasn't really a 'Saga' and it is quite painful to maintain.
from jasper.
Alrighty then, time to flesh this one out. While doing some research on the 1st app we've targeted to switch to Jasper I noticed that it was using sagas, so time to move this up.
Basic syntax ideas:
// Base class that marks the handler type as a stateful saga,
// where "T" is the state type for the saga.
public abstract class Saga<T>
{
public bool IsCompleted {get;set;}
public void MarkCompleted()
{
IsCompleted = true;
}
}
public class InvoiceSaga : Saga<Invoice>
{
public T Starts(Message1)
{
// do stuff
}
// or
public Task<T> Starts(Message1)
{
}
// Can use Handle/Consume() methods for other actions as normal
// Also use Orchestrates() to be compatible w/ previous FubuMVC code
// Jasper will generate code that will look up the saga state object for the message
// type and pass that into the method here
public void Handles(Message message, Invoice invoice)
{
}
// Need some way to pick off the identity for the saga state object
// from the incoming message. This is one possibility.
// If we do this, it will honor base types
// Thinking that we'd support Guid, int, long, and string as valid identity
// types
public Guid Identity(Message message) => message.SagaId;
}
public class Envelope
{
// If you don't wanna have to stick the saga id inside the messages
// Gonna be a little annoying to track this, but have it set in cascading messages
public string SagaId {get;set;}
}
Tasks:
- Discover handler actions on classes that inherit from
Saga<T>
- Track SagaId on envelopes in cascading messages
- Policy that wraps saga persistence BlueMilk frames around the handlers
- Marten-backed saga persistence. Codegen in the handling around it
- Find the saga identity from message.SagaId (convention)
- Respect a
[SagaId]
attribute on the message types as another alternative - Find the saga identity from HandlerClass.Identity(message type)
- Respect the Creates() methods
- Respect the IsCompleted() method and handling
from jasper.
This description matches what I remember from the conversation. A few questions though:
- What will the Creates() method do?
- Does the Envelope.SagaId identify the saga that is receiving the message, or the one that is sending it? For example, if saga A sends a message that starts saga B, and saga B's
Starts
method returns a message back to saga A, which SagaId is in that response message envelope? - Do we still want to call it a "saga" to match common usage even though it won't include built-in support for rollback/compensation like the original definition of a saga would? Or is this a good opportunity to name it based on the process manager pattern which seems to be a better description?
from jasper.
Sorry for the delay.
Creates()
was meant to be "initiates the long running saga". If that's confusing, I'd go for "Start()" instead, but definitely not "Initiates()" 'cause folks would never spell it right. Could just say that any Handler method that returns the Saga state object is a de facto creator, but I think that'd be confusing
Envelope.SagaId
would be the current saga id referring to the state of the saga. If we have the tracking to the original & parent envelope id's, we have some way of correlating everything in the end, so I'd probably just leave that be. I'm not nearly as worried about forcing users to have the saga id somewhere in the message bodies.
As for the naming, I think far more people are going to be familiar with "saga" in terms of service bus tooling where it's really just a stateful, long running process.
from jasper.
Meh, I'm going to push this one off to a future 0.7.0 release. I hate trying to even do this w/o any kind of early adopter or sample apps first.
from jasper.
Can you give an example of how you see Creates()
working? In our internal Saga code we went with the idea of the marker interface which starts a new saga. I'm curious how this would differ?
from jasper.
@ShaneCourtrille It would work the same way. The naming convention just tips Jasper off that this starts a brand new saga of this type. Using the naming convention also lets you have multiple entry points to start the stateful saga
from jasper.
@ShaneCourtrille And I think I'll call it "Start" instead.
from jasper.
Now then, how do we find the saga state Id for a message? I think in this order:
- SagaId property on the envelope, which would be a new "saga-id" header
- SagaId property on the message type
- [SagaId] attribute on a property on the message type
- Identity(message) method on the handler type
from jasper.
The basic support for Marten-backed sagas is done in ceb43c1.
I'll be opening additional issues for Sql Server backed persistence and there are a bunch of others for "advanced" usages and hardening the usage.
from jasper.
Related Issues (20)
- Middleware convention for Marten command handlers
- Users should be able to make subscriptions against Marten events as they're being captured
- ICommandInvoker<T> for fast "Mediator" approaches in ASP.Net Core pages
- Exception handling overhaul for 2.0
- Add "exception message contains" filtering to the error handling fluent interface HOT 1
- Quick configuration policy to mark all endpoints as being durable in one line of code HOT 1
- Saga Simplification for 2.0 HOT 1
- ICommandBus.EnqueueAsync() should accept a cancellation token HOT 1
- Evaluate whether pausing or circuit breaker on local queue is legal
- Durability agent should be aware of paused listeners HOT 2
- JasperOptions should be sealed
- Make inbox/outbox nomenclature consistent across the code
- The Rabbit MQ conventional routing needs an allow and/or deny list feature
- Documentation on runtime pipeline
- Add a sample in documentation of bootstrapping a headless service in .NET 6
- Sagas need to support a static `Start()` method that returns the Saga state
- Should be legal for "NotFound" methods on sagas to be static HOT 1
- Per endpoint JSON serialization customization HOT 1
- Misnamed Project Causing *nix Build Failure HOT 1
- System.IO.FileNotFoundException: Could not load file or assembly 'JasperFx.Core, Version=1.4.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified. HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jasper.