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

Import third-party events #1152

Merged
merged 51 commits into from
Sep 4, 2019
Merged

Import third-party events #1152

merged 51 commits into from
Sep 4, 2019

Conversation

dmdashenkov
Copy link
Contributor

@dmdashenkov dmdashenkov commented Aug 30, 2019

In this PR we introduce new API for posting events into a Bounded Context manually.

Mitivation

In real-life projects, often there are upstream third-party systems to integrate with. Such systems may emit events. However, constructing an instance of io.spine.core.Event and posting it into the corrent EventBus may be cumbersome, as well as error-prone, since the Event type is the internal API of the framework.

API

ThirdPartyContext is an adapter for external systems. ThirdPartyContext represents an external system as if it was just another Bounded Context. The adapter posts submitted by the user events to other Bounded Contexts via the common transport.

Typical usage looks as follows:

ThirdPartyContext gitHub = ThirdPartyContext.multitenant("GitHub");
ActorContext actor = ActorContext
        .newBuilder()
        .setUserId(/* ... */)
        .setTimestamp(/* ... */)
        .setTenantId(/* ... */) // A tenant ID is required for a multitenant Context.
        .vBuild();
EventMessage event = IssueClosed
        .newBuilder()
        // ...
        .vBuild();
gitHub.emittedEvent(event, actor);

Further Improvements

The next step for this feature is to allow events going through the IntegrationBus be posted into the domestic EventBus so that they are stored in the domestic EventStore for catch up and audit.

Other Changes

This PR also re-enabled the 3 disabled tests in the server module. 2 of them used to fail due to unimplemented functionality and the third one is just too slow. All the tests now pass. The slow one is marked as SlowTest so that it can be skipped locally by running fastTest Gradle task instead of test.

@dmdashenkov dmdashenkov self-assigned this Aug 30, 2019
@codecov
Copy link

codecov bot commented Aug 30, 2019

Codecov Report

Merging #1152 into master will increase coverage by 0.18%.
The diff coverage is 87.05%.

@@             Coverage Diff              @@
##             master    #1152      +/-   ##
============================================
+ Coverage     91.43%   91.61%   +0.18%     
- Complexity     4208     4227      +19     
============================================
  Files           544      545       +1     
  Lines         13248    13309      +61     
  Branches        778      782       +4     
============================================
+ Hits          12113    12193      +80     
+ Misses          880      859      -21     
- Partials        255      257       +2

@dmdashenkov dmdashenkov marked this pull request as ready for review September 2, 2019 10:05
@dmdashenkov
Copy link
Contributor Author

@alexander-yevsyukov, @dmitrykuzmin, PTAL again.

Copy link
Contributor

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my comments.

* Creates a new single-tenant instance of {@code ThirdPartyContext} with the given name.
*
* @param name
* name of the third-party system
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we create is our representation of a part of a 3rd party system, as if it was a Bounded Context. So, I'd say this: “A name of a Context which represents a part of a third-party system.“ Anyway, it should say that it's not the whole system.

* name of the third-party system
*/
public static ThirdPartyContext singleTenant(String name) {
checkNotNull(name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check for an empty string too, please?

* name of the third-party system
*/
public static ThirdPartyContext multitenant(String name) {
checkNotNull(name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check for an empty string too, please?

private static ThirdPartyContext newContext(String name, boolean multitenant) {
BoundedContext context = notStoringEvents(name, multitenant).build();
context.integrationBus()
.notifyOfCurrentNeeds();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to name this method so that it tells about the fact that Contexts need to speak to each other, maybe again, because a new context appeared in the whole picture of the system.

checkNotNull(eventMessage);
checkTenant(actorContext, eventMessage);

EventId id = EventId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Events.generateId() does not work here?

.newBuilder()
.setValue(newUuid())
.build();
EventContext eventContext = EventContext
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please have EventFactory to avoid generating event IDs and assembling Event instances. We need to encapsulate these details of creating events even.

.get();
return result;
if (count != 1) {
logWrongMethodCount(count, targetType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please test this branch.

@dmdashenkov
Copy link
Contributor Author

@alexander-yevsyukov, PTAL again.

Copy link
Contributor

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my comments.

@@ -32,12 +33,13 @@
/**
* The signature of {@link EventReactorMethod}.
*/
final class EventReactorSignature extends EventAcceptingSignature<EventReactorMethod> {
@Internal
public final class EventReactorSignature extends EventAcceptingSignature<EventReactorMethod> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we hide this class back?

@@ -89,7 +89,7 @@ public void handle(ExternalMessage value) {
clearStaleSubscriptions(request.getRequestedMessageTypeList(), origin);
if (!knownContexts.contains(origin)) {
knownContexts.add(origin);
integrationBus.notifyOfCurrentNeeds();
integrationBus.introduceSelf();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't sound right. The bus is already introduced to the system. It's the new context which introduces itself. Or, if you want the bus to do the job the method should be named differently.

*/
_error().log(
"There are %d handler methods found for the type `%s`." +
"Expected only one. Model is corrupt.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Model is corrupt

This doesn't tell the reader much of info. It just scares him. Tell the reader what to do about the problem.
Please include method names into diagnostics.

return handler;
}

private IllegalStateException wrongMethodCount(Collection<H> handlers, M targetType) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make this a state-check method and name it checkOnlyOne().

@dmdashenkov
Copy link
Contributor Author

@alexander-yevsyukov, PTAL again.

Copy link
Contributor

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dmdashenkov dmdashenkov merged commit 21a252e into master Sep 4, 2019
@dmdashenkov dmdashenkov deleted the import-3d-party-events branch September 4, 2019 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants