{"action":"created","issue":{"url":"https://api.github.com/repos/SpineEventEngine/core-java/issues/829","repository_url":"https://api.github.com/repos/SpineEventEngine/core-java","labels_url":"https://api.github.com/repos/SpineEventEngine/core-java/issues/829/labels{/name}","comments_url":"https://api.github.com/repos/SpineEventEngine/core-java/issues/829/comments","events_url":"https://api.github.com/repos/SpineEventEngine/core-java/issues/829/events","html_url":"https://github.com/SpineEventEngine/core-java/pull/829","id":354334659,"node_id":"MDExOlB1bGxSZXF1ZXN0MjExMTIxNzkz","number":829,"title":"System-Backed Entity Idempotency","user":{"login":"dmdashenkov","id":18305364,"node_id":"MDQ6VXNlcjE4MzA1MzY0","avatar_url":"https://avatars1.githubusercontent.com/u/18305364?v=4","gravatar_id":"","url":"https://api.github.com/users/dmdashenkov","html_url":"https://github.com/dmdashenkov","followers_url":"https://api.github.com/users/dmdashenkov/followers","following_url":"https://api.github.com/users/dmdashenkov/following{/other_user}","gists_url":"https://api.github.com/users/dmdashenkov/gists{/gist_id}","starred_url":"https://api.github.com/users/dmdashenkov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dmdashenkov/subscriptions","organizations_url":"https://api.github.com/users/dmdashenkov/orgs","repos_url":"https://api.github.com/users/dmdashenkov/repos","events_url":"https://api.github.com/users/dmdashenkov/events{/privacy}","received_events_url":"https://api.github.com/users/dmdashenkov/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":{"login":"dmdashenkov","id":18305364,"node_id":"MDQ6VXNlcjE4MzA1MzY0","avatar_url":"https://avatars1.githubusercontent.com/u/18305364?v=4","gravatar_id":"","url":"https://api.github.com/users/dmdashenkov","html_url":"https://github.com/dmdashenkov","followers_url":"https://api.github.com/users/dmdashenkov/followers","following_url":"https://api.github.com/users/dmdashenkov/following{/other_user}","gists_url":"https://api.github.com/users/dmdashenkov/gists{/gist_id}","starred_url":"https://api.github.com/users/dmdashenkov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dmdashenkov/subscriptions","organizations_url":"https://api.github.com/users/dmdashenkov/orgs","repos_url":"https://api.github.com/users/dmdashenkov/repos","events_url":"https://api.github.com/users/dmdashenkov/events{/privacy}","received_events_url":"https://api.github.com/users/dmdashenkov/received_events","type":"User","site_admin":false},"assignees":[{"login":"dmdashenkov","id":18305364,"node_id":"MDQ6VXNlcjE4MzA1MzY0","avatar_url":"https://avatars1.githubusercontent.com/u/18305364?v=4","gravatar_id":"","url":"https://api.github.com/users/dmdashenkov","html_url":"https://github.com/dmdashenkov","followers_url":"https://api.github.com/users/dmdashenkov/followers","following_url":"https://api.github.com/users/dmdashenkov/following{/other_user}","gists_url":"https://api.github.com/users/dmdashenkov/gists{/gist_id}","starred_url":"https://api.github.com/users/dmdashenkov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dmdashenkov/subscriptions","organizations_url":"https://api.github.com/users/dmdashenkov/orgs","repos_url":"https://api.github.com/users/dmdashenkov/repos","events_url":"https://api.github.com/users/dmdashenkov/events{/privacy}","received_events_url":"https://api.github.com/users/dmdashenkov/received_events","type":"User","site_admin":false}],"milestone":null,"comments":2,"created_at":"2018-08-27T14:09:19Z","updated_at":"2018-08-29T14:45:46Z","closed_at":null,"author_association":"CONTRIBUTOR","pull_request":{"url":"https://api.github.com/repos/SpineEventEngine/core-java/pulls/829","html_url":"https://github.com/SpineEventEngine/core-java/pull/829","diff_url":"https://github.com/SpineEventEngine/core-java/pull/829.diff","patch_url":"https://github.com/SpineEventEngine/core-java/pull/829.patch"},"body":"# Entity Idempotency\r\nFrom now, `Projection`s and `ProcessManager`s are idempotent to commands and events dispatched to them (as well as the `Aggregates`).\r\n\r\n## Message dispatching flow\r\n 1. A message is dispatched to a record-based entity.\r\n 2. The repository sends a system command to the associated `EntityHistory`\r\n 3. The `EntityHistory` checks if the message has been recently handled.\r\n 4. If the `EntinyHistory` discovers that the message is a duplicate, it produces a rejection. Otherwise, it allows the message dispatching by producing a corresponding event.\r\n 5. The repository listens to those events and rejections and either completes the message dispatching or reports about the error.\r\n\r\n## System Event Types\r\n\r\nWhen dispatching a command to an `Aggregate` or a `ProcessManager`, the system bounded context produces either `CommandDispatchedToHandler` event or `CannotDispatchCommandTwice` rejection.\r\n\r\nWhen dispatching an event to an `Aggregate` or a `ProcessManeger`, the system bounded context produces either `EventDispatchedToReactor` event or `CannotDispatchEventTwice` rejection. \r\n\r\nWhen dispatching an event to a `Projection`, the system bounded context produces either `EventDispatchedToSubscriber` event or `CannotDispatchEventTwice` rejection. \r\n\r\nA framework user may subscribe to these events and rejections.\r\n_Warning:_ never use entities to listen to the system events, since that would produce an endless stream of commands and events traveling between the domain and system contexts. The only safe way to listen to a system event is to use an `AbstractEventSubscriber` descendant.\r\n\r\n## Implementation Details\r\n\r\nThe depth of the duplicate lookup is the size of the `RecentHistory` of the `EntityHistory` aggregate. It is currently impossible to configure this value.\r\n\r\n## Aggregate Idempotency\r\n\r\nThe mechanism of `Aggregate` idempotency has not changed. However, `Aggreagte`s are now idempotent to events on which they react, as well as to the commands.\r\n\r\nThough the system events and rejections are produced for the aggregate as well as for the record-based entities, the aggregate repository does not rely on the system context to deliver its messages.\r\n\r\n## Concurrent Dispatching\r\n\r\nSince a record-based repository relies on the system context messages, it does not block the execution in order to dispatch a given message to its targets. For instance, an event is dispatched to a `Projection` as follows:\r\n 1. The repository receives the event and determines its target(s).\r\n 2. The repository sends a system command. After this stage, the thread is released.\r\n 3. The repository receives the system event or rejection and performs (or does not, in case of the rejection) the event delivery.\r\n\r\nBetween steps 2 and 3, the thread typically can perform some other work.\r\n_Note:_ the dispatching is truly concurrent if the `TransportFactory` used by the bounded context is non-blocking. In case of the default in-memory transport (or any other _blocking_) transport, the dispatching is performed as a single operation.\r\n\r\n# Other Changes\r\n## Routing\r\n\r\nFrom now on, the `EntityMessageEndpoint`s are not responsible for the message routing. Instead, they are told whom to deliver the message to. The routing is performed by the `Repository` itself.\r\n\r\n## `EventContext`\r\n\r\nIn the `EventContext`, we introduce a new `origin_id` `oneof` group. The group consists of `command_id` and `event_id` fields, which represent the ID of the origin message of the associated event."},"comment":{"url":"https://api.github.com/repos/SpineEventEngine/core-java/issues/comments/416980618","html_url":"https://github.com/SpineEventEngine/core-java/pull/829#issuecomment-416980618","issue_url":"https://api.github.com/repos/SpineEventEngine/core-java/issues/829","id":416980618,"node_id":"MDEyOklzc3VlQ29tbWVudDQxNjk4MDYxOA==","user":{"login":"dmdashenkov","id":18305364,"node_id":"MDQ6VXNlcjE4MzA1MzY0","avatar_url":"https://avatars1.githubusercontent.com/u/18305364?v=4","gravatar_id":"","url":"https://api.github.com/users/dmdashenkov","html_url":"https://github.com/dmdashenkov","followers_url":"https://api.github.com/users/dmdashenkov/followers","following_url":"https://api.github.com/users/dmdashenkov/following{/other_user}","gists_url":"https://api.github.com/users/dmdashenkov/gists{/gist_id}","starred_url":"https://api.github.com/users/dmdashenkov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dmdashenkov/subscriptions","organizations_url":"https://api.github.com/users/dmdashenkov/orgs","repos_url":"https://api.github.com/users/dmdashenkov/repos","events_url":"https://api.github.com/users/dmdashenkov/events{/privacy}","received_events_url":"https://api.github.com/users/dmdashenkov/received_events","type":"User","site_admin":false},"created_at":"2018-08-29T14:45:46Z","updated_at":"2018-08-29T14:45:46Z","author_association":"CONTRIBUTOR","body":"@armiol, PTAL."}}
{"actor":{"display_login":"dmdashenkov"}}