-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(platform): connect to the host periodically when starting the pla…
…tform When connecting to the host and if the client does not receive connect acknowledgement in time, the client will resend the connect request. A single connect request may not be sufficient if, for example, the microfrontends are to be integrated into a rich client. For example, an integrator may want to bridge messages to a remote host. If the integrator cannot hook into the message bus in time, the client's connection request may be lost. Therefore, the gateway initiates the connection request at regular intervals until it receives an acknowledgement.
- Loading branch information
1 parent
bb044f1
commit 788a444
Showing
5 changed files
with
158 additions
and
20 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
projects/scion/microfrontend-platform/src/lib/client/client-connect.script.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright (c) 2018-2020 Swiss Federal Railways | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*/ | ||
|
||
import {MicrofrontendPlatform} from '../microfrontend-platform'; | ||
import {Beans} from '@scion/toolkit/bean-manager'; | ||
import {Observer} from 'rxjs'; | ||
import {ɵBrokerGateway} from './messaging/broker-gateway'; | ||
|
||
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); | ||
|
||
for (let i = 1; i < connectCount; i++) { | ||
const {clientId} = await Beans.get(ɵBrokerGateway).connectToBroker(); | ||
observer.next(clientId); | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
projects/scion/microfrontend-platform/src/lib/client/client-connect.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* Copyright (c) 2018-2020 Swiss Federal Railways | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*/ | ||
import {MicrofrontendPlatform} from '../microfrontend-platform'; | ||
import {MicrofrontendFixture} from '../testing/microfrontend-fixture/microfrontend-fixture'; | ||
import {firstValueFrom, timer} from 'rxjs'; | ||
import {ManifestFixture} from '../testing/manifest-fixture/manifest-fixture'; | ||
import {Beans} from '@scion/toolkit/bean-manager'; | ||
import {ClientRegistry} from '../host/client-registry/client.registry'; | ||
import {ObserveCaptor} from '@scion/toolkit/testing'; | ||
|
||
describe('MicrofrontendPlatform', () => { | ||
|
||
const disposables = new Set<Disposable>(); | ||
|
||
beforeEach(async () => { | ||
await MicrofrontendPlatform.destroy(); | ||
}); | ||
|
||
afterEach(async () => { | ||
await MicrofrontendPlatform.destroy(); | ||
disposables.forEach(disposable => disposable()); | ||
}); | ||
|
||
it('should throw if not connected to the host within the configured timeout', async () => { | ||
const microfrontendFixture = registerFixture(new MicrofrontendFixture()).insertIframe(); | ||
const connectPromise = microfrontendFixture.loadScript('./lib/client/client-connect.script.ts', 'connectToHost', {symbolicName: 'client', brokerDiscoverTimeout: 250}); | ||
await expectAsync(connectPromise).toBeRejectedWithError(/\[GatewayError] Message broker not discovered within 250ms/); | ||
}); | ||
|
||
it('should retry to connect to the host', async () => { | ||
// Mount the client before starting the host, which means that the first connect request(s) are never answered. | ||
const microfrontendFixture = registerFixture(new MicrofrontendFixture()).insertIframe(); | ||
const connectPromise = microfrontendFixture.loadScript('./lib/client/client-connect.script.ts', 'connectToHost', {symbolicName: 'client', brokerDiscoverTimeout: 2000}); | ||
await firstValueFrom(timer(1000)); | ||
|
||
// Start the host a little bit later. | ||
await MicrofrontendPlatform.startHost({ | ||
applications: [ | ||
{ | ||
symbolicName: 'client', | ||
manifestUrl: new ManifestFixture({name: 'Client'}).serve(), | ||
}, | ||
], | ||
}); | ||
|
||
// Expect client to be connected | ||
await expectAsync(connectPromise).toBeResolved(); | ||
const clientId = await firstValueFrom(microfrontendFixture.message$); | ||
expect(Beans.get(ClientRegistry).getByClientId(clientId)).withContext('expected "client" to be CONNECTED').toBeDefined(); | ||
}); | ||
|
||
it('should ignore duplicate connect request of the same client', async () => { | ||
await MicrofrontendPlatform.startHost({ | ||
applications: [ | ||
{ | ||
symbolicName: 'client', | ||
manifestUrl: new ManifestFixture({name: 'Client'}).serve(), | ||
}, | ||
], | ||
}); | ||
|
||
const microfrontendFixture = registerFixture(new MicrofrontendFixture()).insertIframe(); | ||
await microfrontendFixture.loadScript('./lib/client/client-connect.script.ts', 'connectToHost', {symbolicName: 'client', connectCount: 3}); | ||
|
||
const clients = Beans.get(ClientRegistry).getByApplication('client'); | ||
expect(clients.length).toBe(1); | ||
const clientId = clients[0].id; | ||
|
||
const clientIdCaptor = new ObserveCaptor(); | ||
microfrontendFixture.message$.subscribe(clientIdCaptor); | ||
|
||
expect(clientIdCaptor.getValues()).toEqual([clientId, clientId, clientId]); | ||
}); | ||
|
||
/** | ||
* Registers the fixture for destruction after test execution. | ||
*/ | ||
function registerFixture(fixture: MicrofrontendFixture): MicrofrontendFixture { | ||
disposables.add(() => fixture.removeIframe()); | ||
return fixture; | ||
} | ||
}); | ||
|
||
type Disposable = () => void; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters