Skip to content

Commit

Permalink
perf(platform/messaging): transport intents to subscribed clients only
Browse files Browse the repository at this point in the history
Previously, an intent was transported to all qualified clients regardless of whether the client had a subscription for the intent, causing unnecessary messaging delivery and is a prerequisite for supporting retained intents.

closes #124
  • Loading branch information
danielwiehl committed Oct 21, 2022
1 parent 5ad9675 commit 2b1a603
Show file tree
Hide file tree
Showing 30 changed files with 966 additions and 644 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export class PublishMessageComponent implements OnDestroy {
try {
if (requestReply) {
this._requestResponseSubscription = this._intentClient.request$({type, qualifier}, message, {headers: headers})
.pipe(finalize(() => this.markPublishing(true)))
.pipe(finalize(() => this.markPublishing(false)))
.subscribe({
next: reply => this.replies.push(reply),
error: error => this.publishError = error,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ To learn more about an intention, see chapter <<chapter:intention-api:intention>
[[chapter:intent-based-messaging:issuing-an-intent]]
[discrete]
=== Issuing an Intent
A micro application can issue intents for intentions declared in its manifest. The platform transports the intent to micro applications that provide a fulfilling capability. Along with the intent, you can pass transfer data, either as payload, message headers or parameters. Passed data must be serializable with the _Structured Clone Algorithm_.
A micro application can issue intents for intentions declared in its manifest. The platform transports the intent to micro applications that provide a fulfilling capability. Along with the intent, the application can pass transfer data, either as payload, message headers or parameters. Passed data must be serializable with the _Structured Clone Algorithm_.

The following code snippet illustrates starting the checkout wizard via intent.

Expand Down Expand Up @@ -98,7 +98,7 @@ To learn more about a capability, see chapter <<chapter:intention-api:capability
[[chapter:intent-based-messaging:handling-intents]]
[discrete]
=== Handling Intents
Intents are transported to all micro application instances that provide a fulfilling capability. Intents are typically handled in an activator. An activator is a special microfrontend that a micro application can provide to interact with the platform. Activators are loaded when starting the host application and run for the entire application lifecycle. An activator microfrontend is special in that it is never displayed to the user. Learn more about activator in the chapter <<chapter:activator>>.
Intents are transported to applications that provide a fulfilling capability and are typically subscribed to in an activator. An activator is a special microfrontend that a micro application can provide to interact with the platform. Activators are loaded when starting the host application and run for the entire application lifecycle. An activator microfrontend is special in that it is never displayed to the user. Learn more about activator in the chapter <<chapter:activator>>.

The following code snippet illustrates how to listen to intents.

Expand All @@ -109,7 +109,7 @@ include::intent-based-messaging.snippets.ts[tags=handle-intent]
<1> Defines the selector to filter intents. Without a selector, you would receive all intents you have defined a capability for. The selector supports the use of wildcards in the qualifier.
<2> Subscribes to intents that match the selector.

IMPORTANT: A micro application only receives intents for which it provides a respective capability. The selector is used as a filter only.
IMPORTANT: A micro application only receives intents for which it provides a fulfilling capability. The selector is used as a filter only.

[[chapter:intent-based-messaging:request-response-message-exchange-pattern]]
[discrete]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ The following code snippet shows an example of how an application can subscribe
include::intention-api.snippets.ts[tags=intent-handling]
----

IMPORTANT: A micro application only receives intents for which it provides a respective capability. The selector is used as a filter only.
IMPORTANT: A micro application only receives intents for which it provides a fulfilling capability. The selector is used as a filter only.

For more information about handling an intent, see the chapter <<chapter:intent-based-messaging:handling-intents>> in <<chapter:intent-based-messaging>>.

Expand Down Expand Up @@ -252,7 +252,7 @@ include::intention-api.snippets.ts[tags=capability-lookup-toolbar-items]

NOTE: To see how to handle intents in the capability providing micro application, see the chapter <<chapter:intent-based-messaging:handling-intents>> in <<chapter:intent-based-messaging>>.

By passing a `ManifestObjectFilter` to the `lookupCapabilities$` method, you can control which capabilities to observe. Specified filter criteria are "AND"ed together. If not passing a filter, all capabilities visible to the requesting micro application are observed. When subscribing to the Observable, it emits the requested capabilities. The Observable never completes and emits continuously when satisfying capabilities are registered or unregistered.
By passing a `ManifestObjectFilter` to the `lookupCapabilities$` method, you can control which capabilities to observe. Specified filter criteria are "AND"ed together. If not passing a filter, all capabilities visible to the requesting micro application are observed. When subscribing to the Observable, it emits the requested capabilities. The Observable never completes and emits continuously when fulfilling capabilities are registered or unregistered.

IMPORTANT: A micro application can only look up its own capabilities and public capabilities for which it has declared an intention.

Expand Down Expand Up @@ -290,7 +290,7 @@ a| `string`
=== Browsing Intentions
The platform allows you to browse and observe intentions. Unlike <<chapter:intention-api:capability-lookup,browsing capabilities>>, an application can browse the intentions of all micro applications. The use case for browsing intentions is somewhat technical, e.g., used by the _DevTools_ to list intentions declared by micro applications.

You can browse intentions using the `ManifestService.lookupIntentions$` method. By passing a `ManifestObjectFilter` to the `lookupIntentions$` method, you can control which intentions to observe. Specified filter criteria are "AND"ed together. If not passing a filter, all intentions are observed. When subscribing to the Observable, it emits the requested intentions. The Observable never completes and emits continuously when satisfying intentions are registered or unregistered.
You can browse intentions using the `ManifestService.lookupIntentions$` method. By passing a `ManifestObjectFilter` to the `lookupIntentions$` method, you can control which intentions to observe. Specified filter criteria are "AND"ed together. If not passing a filter, all intentions are observed. When subscribing to the Observable, it emits the requested intentions. The Observable never completes and emits continuously when matching intentions are registered or unregistered.

.Properties of `ManifestObjectFilter` to filter intentions
[cols="1,2,1,8"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export namespace IntendBasedMessagingSpecs {
}

/**
* Tests that an intent can only be issued if there is one application at minimum providing a respective capability.
* Tests that an intent can only be issued if there is one application at minimum providing a fulfilling capability.
*/
export async function intentNotFulfilledSpec(testingAppPO: TestingAppPO): Promise<void> {
const pagePOs = await testingAppPO.navigateTo({
Expand Down Expand Up @@ -935,7 +935,7 @@ export namespace IntendBasedMessagingSpecs {
}

/**
* Tests that the platform resolves to the satisfying capability.
* Tests that the platform resolves to the fulfilling capability.
*/
export async function resolveCapabilitySpec(testingAppPO: TestingAppPO): Promise<void> {
const pagePOs = await testingAppPO.navigateTo({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {filterByTransport} from '../operators';

export async function connectToHost({symbolicName, brokerDiscoverTimeout, connectCount}, observer: Observer<string>): Promise<void> { // eslint-disable-line @typescript-eslint/typedef
await MicrofrontendPlatform.connectToHost(symbolicName, {brokerDiscoverTimeout});
observer.next(Beans.get(ɵBrokerGateway).brokerInfo.clientId);
observer.next(Beans.get(ɵBrokerGateway).session.clientId);

for (let i = 1; i < connectCount; i++) {
const {clientId} = await Beans.get(ɵBrokerGateway).connectToBroker();
Expand All @@ -29,7 +29,7 @@ export async function connectToHost({symbolicName, brokerDiscoverTimeout, connec
export async function connectClientToRemoteHost({symbolicName, brokerDiscoverTimeout}, observer: Observer<string>): Promise<void> { // eslint-disable-line @typescript-eslint/typedef
Beans.register(ɵWINDOW_TOP, {useValue: window}); // simulate to be loaded into the top-level window
await MicrofrontendPlatform.connectToHost(symbolicName, {brokerDiscoverTimeout});
observer.next(Beans.get(ɵBrokerGateway).brokerInfo.clientId);
observer.next(Beans.get(ɵBrokerGateway).session.clientId);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ export async function connectToHost({symbolicName, disconnectOnUnloadDisabled =
Beans.register(VERSION, {useValue: version});
}
await MicrofrontendPlatform.connectToHost(symbolicName);
observer.next(Beans.get(ɵBrokerGateway).brokerInfo.clientId);
observer.next(Beans.get(ɵBrokerGateway).session.clientId);
}

export async function connectToHostThenStopPlatform({symbolicName}, observer: Observer<string>): Promise<void> { // eslint-disable-line @typescript-eslint/typedef
await MicrofrontendPlatform.connectToHost(symbolicName);
observer.next(Beans.get(ɵBrokerGateway).brokerInfo.clientId);
observer.next(Beans.get(ɵBrokerGateway).session.clientId);
await MicrofrontendPlatform.destroy();
}

export async function connectToHostThenLocationHref({symbolicName, locationHref}, observer: Observer<string>): Promise<void> { // eslint-disable-line @typescript-eslint/typedef
await MicrofrontendPlatform.connectToHost(symbolicName);
observer.next(Beans.get(ɵBrokerGateway).brokerInfo.clientId);
observer.next(Beans.get(ɵBrokerGateway).session.clientId);
window.location.href = locationHref;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class ManifestService implements Initializer {
* to match any value, e.g., `{property: '*'}`, or partial matching to find capabilities with at least the specified qualifier
* properties. Partial matching is enabled by appending the _any-more_ entry to the qualifier, as following: `{'*': '*'}`.
* @return An Observable that, when subscribed, emits the requested capabilities.
* It never completes and emits continuously when satisfying capabilities are registered or unregistered.
* It never completes and emits continuously when fulfilling capabilities are registered or unregistered.
*/
public lookupCapabilities$<T extends Capability>(filter?: ManifestObjectFilter): Observable<T[]> {
return Beans.get(MessageClient).request$<T[]>(ManifestRegistryTopics.LookupCapabilities, filter)
Expand All @@ -100,7 +100,7 @@ export class ManifestService implements Initializer {
* to match any value, e.g., `{property: '*'}`, or partial matching to find intentions with at least the specified qualifier
* properties. Partial matching is enabled by appending the _any-more_ entry to the qualifier, as following: `{'*': '*'}`.
* @return An Observable that, when subscribed, emits the requested intentions.
* It never completes and emits continuously when satisfying intentions are registered or unregistered.
* It never completes and emits continuously when matching intentions are registered or unregistered.
*/
public lookupIntentions$(filter?: ManifestObjectFilter): Observable<Intention[]> {
return Beans.get(MessageClient).request$<Intention[]>(ManifestRegistryTopics.LookupIntentions, filter)
Expand Down
Loading

0 comments on commit 2b1a603

Please sign in to comment.