Comments (7)
It feels weird to have commands that are dispatched later.
It seems better to have some kind of timed process (which should be a PM probably, and we already talked about PMs and timers) which just sends the command later. Just a ExpireOrder command that changes the state of the Order, no? Besides, a PM can control the expiring process if the command is dropped for any reason, something you can't do if you just send a delayed command once.
from commanded.
It's possible to implement time-based triggers using an external job scheduler and by dispatching commands to raise events to set the callback time period (date time, recurring interval) and command to dispatch.
A standard event hander would then configure the job scheduler at the requested period to dispatch the command. This requires no changes to Commanded itself. It could be implemented as a standalone library.
from commanded.
Why? Is there anyone who needs this?
I agree with @Papipo that it should be done in PM. This seems to me like a business concern, and so it should not be done in a framework. Unless you need timers for things like periodic snapshotting etc. But that is not what you're talking about here, I think.
from commanded.
Closing, could be implemented as an external library.
from commanded.
Hey guys, could we please discuss this proposal once more. The PM triggers are different from scheduled commands. Say we have a PM which need to check order status every minute since order creation, by calling external http service. Currently it means that we'll need to post command CheckOrderStatus
once in minute, it will be processed by aggregate and emit OrderStatusRequested
event which then will be handled by PM. In domain terms, this is almost meaningless event, the only purpose of it - is run PM handler (and eventstore will contain tons of them). So why can't we just trigger PM directly? I could imagine something like this:
defmodule ProcessManager do
# ...
def handle_trigger(%ProcessManager{}, %CheckOrderStatus{order_id: order_id}) do
# note %CheckOrderStatus{} is a not domain event and not persist in event store
case MyApi.get_order_status(order_id) do
{:ok, :complete} -> %CompleteOrder{id: order_id)
_ -> []
end
end
# ...
def handle(%ProjectManager{id: id}, %OrderOpened{}), do: MyScheduler.add_job("* * * * *",{TriggerProcessManager, [id: id]})
def handle(%ProjectManager{id: id}, %OrderClosed{}), do: MyScheduler.remove_job(id)
# ...
end
defmodule TriggerProcessManager do
# ...
def perform(id: id) do
ProcessManager.trigger(id, %CheckOrderStatus{order_id: i})
end
# ...
end
does it makes any sense for you guys?
from commanded.
@ayarulin I'm currently building a library for Commanded to support one-off and recurring commands: Commanded scheduler.
This library allows you to directly schedule commands:
alias Commanded.Scheduler
# schedule one-off command
Scheduler.schedule_once(reservation_id, %TimeoutReservation{..}, ~N[2020-01-01 12:00:00])
# schedule a recurring command to execute every 15 minutes
Scheduler.schedule_recurring(reservation_id, %TimeoutReservation{..}, "*/15 * * * *")
It also supports scheduling commands from a process manager by returning a schedule once or schedule recurring command:
defmodule OrderStatusProcessManager do
use Commanded.ProcessManagers.ProcessManager,
name: "order-status",
router: AppRouter
def handle(%OrderStatusProcessManager{}, %OrderOpened{order_id: order_id}) do
%Commanded.Scheduler.ScheduleRecurring
schedule_uuid: order_id,
command: %CheckOrderStatus{order_id: order_id},
schedule: "* * * * *",
}
end
def handle(%OrderStatusProcessManager{}, %OrderClosed{order_id: order_id}) do
%CancelSchedule{order_id: order_id}
end
end
Then you'd do the order checking in the command handler:
def OrderHandler do
def handle(%Order{} = order, %CheckOrderStatus{order_id: order_id}) do
case MyApi.get_order_status(order_id) do
{:ok, :complete} -> Order.mark_complete(order)
_ -> []
end
end
end
The benefit of this approach is that process managers are purely functional. They return commands in response to events, thus are easily testable. The details of fetching the external order status can be done in the command handler. The response can be passed into the aggregate to create the appropriate domain event(s).
from commanded.
@slashdotdash, +1 to Commanded Scheduler
and thanks for clarifications, i've totally missed that services can be called from command handlers as well.
The benefit of this approach is that process managers are purely functional
good point
from commanded.
Related Issues (20)
- General design philosophy question: sending email from process manager HOT 4
- update FAQ regarding scheduling HOT 1
- Wiki Testing section is outdated HOT 1
- warning: redefining module Commanded.Serialization.JsonDecoder.Any HOT 2
- Event number gaplessness required?
- Commanded.aggregate_state does not work when aggregate identity has a prefix HOT 10
- Process manager router option not working
- Lessons learned from performance optimization - an unlikely culprit HOT 3
- no function clause matching in Commanded.Commands.Dispatcher.telemetry_stop/3 HOT 1
- Docs questions
- Stacktrace in event handler error? HOT 2
- Paralelization Strategies in EventHandlers
- Should Commanded.Event.Handler support messages from swarm? HOT 2
- Event retention policies?
- please support multiple commanded application with one eventstore HOT 6
- Process Manager state serialization breaks when using a custom TypeProvider with the JsonSerializer
- `Commanded.ProcessManagers.ProcessManager.identity/0` function returns `nil` in unit tests
- no function clause matching in Commanded.Event.Handler.partition_event/4 HOT 1
- EventstoreDB is sunsetting the TCP protocol HOT 1
- Is it a bad practice for an event handler to depend on a projector completion? HOT 2
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 commanded.