@Frank I'm not sure to understand what you are suggesting. I understand that event streams are immutable and that to correct the past you need to take compensatory actions, but I'm not sure how that's relevant to my problem. I'm not using event sourcing anyway, so I might have changes that do not generate events.
Imagine a simple import task that reads data from a data source and creates aggregates in bulk. Such import task is a long running process. In order to gather statistics on the imports I may want to publish the following events:
ImportTaskStarted { importer, dataSource }
ImportTaskCompleted { totalImported }
ImportTaskFailed { failureDetails }
The problem is that if I have something like that in a domain service:
try {
publish(ImportTaskStarted(...));
for data in datasource {
repository.add(createAggregateFromData(data));
}
publish(ImportTaskCompleted(...));
} catch (e) {
publish(ImportTaskFailed(e));
}
And an application service that controls the transaction:
transaction.begin();
subscribe('ImportTaskFailed', transaction.rollback);
subscribe('ImportTaskCompleted', transaction.commit);
startImportTask(...);
Then all the events that were raised wouldn't be stored in the DB because they are raised in the same transaction that gets rolled back (
I'm using the following event publishing approach with a subscriber that stores all events in an event store). I want to perform a rollback because it is easier to reason about the import task if it succeeds or fail as a whole rather than allowing partial completion.
I think what makes it complicated is that I'm trying to do this in bulk. I though it would be easier, but the problem is avoided if every step happens in it's own transaction. However, that would require more work to rollback an import because it would have to be done through compensating actions (rather than a simple rollback) and these may fail as well leaving the system with a half-complete import for a period of time.