Skip to content

Commit

Permalink
Use correlation-id package only for testing (#276)
Browse files Browse the repository at this point in the history
* fix: cleanup transport

* chore: update package-lock

* fix: cleanup runtime

* fix: correct DI usage

* fix: export abstractCorrelator

* fix: handle strange DI behaviour
  • Loading branch information
jkoenig134 committed Sep 19, 2024
1 parent 929c99f commit 7d482b5
Show file tree
Hide file tree
Showing 30 changed files with 135 additions and 68 deletions.
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions packages/runtime/src/Runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { RuntimeConfig } from "./RuntimeConfig";
import { RuntimeLoggerFactory } from "./RuntimeLoggerFactory";
import { RuntimeHealth } from "./types";
import { RuntimeErrors } from "./useCases";
import { AbstractCorrelator } from "./useCases/common/AbstractCorrelator";
import { SchemaRepository } from "./useCases/common/SchemaRepository";

export interface RuntimeServices {
Expand Down Expand Up @@ -111,7 +112,8 @@ export abstract class Runtime<TConfig extends RuntimeConfig = RuntimeConfig> {
public constructor(
protected runtimeConfig: TConfig,
protected loggerFactory: ILoggerFactory,
eventBus?: EventBus
eventBus?: EventBus,
protected correlator?: AbstractCorrelator
) {
this._logger = this.loggerFactory.getLogger(this.constructor.name);

Expand Down Expand Up @@ -184,7 +186,7 @@ export abstract class Runtime<TConfig extends RuntimeConfig = RuntimeConfig> {
this.logger.error(`An error was thrown in an event handler of the transport event bus (namespace: '${namespace}'). Root error: ${error}`);
});

this.transport = new Transport(databaseConnection, transportConfig, eventBus, this.loggerFactory);
this.transport = new Transport(databaseConnection, transportConfig, eventBus, this.loggerFactory, this.correlator);

this.logger.debug("Initializing Transport Library...");
await this.transport.init();
Expand All @@ -202,6 +204,12 @@ export abstract class Runtime<TConfig extends RuntimeConfig = RuntimeConfig> {
}

private async initDIContainer() {
if (this.correlator) {
Container.bind(AbstractCorrelator)
.factory(() => this.correlator!)
.scope(Scope.Request);
}

Container.bind(EventBus)
.factory(() => this.eventBus)
.scope(Scope.Singleton);
Expand Down Expand Up @@ -291,11 +299,11 @@ export abstract class Runtime<TConfig extends RuntimeConfig = RuntimeConfig> {
.scope(Scope.Request);

Container.bind(AnonymousTokenController)
.factory(() => new AnonymousTokenController(this.transport.config))
.factory(() => new AnonymousTokenController(this.transport.config, this.correlator))
.scope(Scope.Singleton);

Container.bind(BackboneCompatibilityController)
.factory(() => new BackboneCompatibilityController(this.transport.config))
.factory(() => new BackboneCompatibilityController(this.transport.config, this.correlator))
.scope(Scope.Singleton);

const schemaRepository = new SchemaRepository();
Expand Down
10 changes: 10 additions & 0 deletions packages/runtime/src/useCases/common/AbstractCorrelator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ICorrelator } from "@nmshd/transport";

export abstract class AbstractCorrelator implements ICorrelator {
public abstract withId<R>(id: string, work: () => R): R;
public abstract withId<R>(work: () => R): R;
public abstract bindId<W extends Function>(id: string, work: W): W;
public abstract bindId<W extends Function>(work: W): W;
public abstract getId(): string | undefined;
public abstract setId(id: string): undefined;
}
41 changes: 25 additions & 16 deletions packages/runtime/src/useCases/common/UseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,45 @@ import { ParsingError, ServalError, ValidationError } from "@js-soft/ts-serval";
import { ApplicationError, Result } from "@js-soft/ts-utils";
import { CoreError } from "@nmshd/core-types";
import { RequestError } from "@nmshd/transport";
import correlator from "correlation-id";
import stringifySafe from "json-stringify-safe";
import { Inject } from "typescript-ioc";
import { AbstractCorrelator } from "./AbstractCorrelator";
import { PlatformErrorCodes } from "./PlatformErrorCodes";
import { RuntimeErrors } from "./RuntimeErrors";
import { IValidator } from "./validation/IValidator";
import { ValidationResult } from "./validation/ValidationResult";

export abstract class UseCase<IRequest, IResponse> {
@Inject private readonly correlator?: AbstractCorrelator;

public constructor(private readonly requestValidator?: IValidator<IRequest>) {}

public async execute(request: IRequest): Promise<Result<IResponse>> {
const callback = async (): Promise<Result<IResponse>> => {
if (this.requestValidator) {
const validationResult = await this.requestValidator.validate(request);
// if no correlator is defined in the DI a broken one without any methods is injected
// we handle this exactly like no correlator is defined
if (typeof this.correlator?.getId === "undefined") {
return await this._executeCallback(request);
}

if (validationResult.isInvalid()) {
return this.validationFailed(validationResult);
}
}
const correlationId = this.correlator.getId();
if (correlationId) return await this.correlator.withId(correlationId, () => this._executeCallback(request));
return await this.correlator.withId(() => this._executeCallback(request));
}

try {
return await this.executeInternal(request);
} catch (e) {
return this.failingResultFromUnknownError(e);
private async _executeCallback(request: IRequest) {
if (this.requestValidator) {
const validationResult = await this.requestValidator.validate(request);

if (validationResult.isInvalid()) {
return this.validationFailed(validationResult);
}
};
}

const correlationId = correlator.getId();
if (correlationId) return await correlator.withId(correlationId, callback);
return await correlator.withId(callback);
try {
return await this.executeInternal(request);
} catch (e) {
return this.failingResultFromUnknownError(e);
}
}

private failingResultFromUnknownError(error: unknown): Result<any> {
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/src/useCases/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./anonymous";
export * from "./common/AbstractCorrelator";
export * from "./common/Base64ForIdPrefix";
export * from "./common/OwnerRestriction";
export * from "./common/RuntimeErrors";
Expand Down
12 changes: 9 additions & 3 deletions packages/runtime/test/lib/RuntimeServiceProvider.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import correlator from "correlation-id";
import { AnonymousServices, ConsumptionServices, DataViewExpander, RuntimeConfig, TransportServices } from "../../src";
import { MockEventBus } from "./MockEventBus";
import { TestRuntime } from "./TestRuntime";
Expand All @@ -18,6 +19,7 @@ export interface LaunchConfiguration {
enableAttributeListenerModule?: boolean;
enableNotificationModule?: boolean;
enableDefaultRepositoryAttributes?: boolean;
useCorrelator?: boolean;
}

export class RuntimeServiceProvider {
Expand Down Expand Up @@ -84,9 +86,13 @@ export class RuntimeServiceProvider {
if (launchConfiguration.enableAttributeListenerModule) config.modules.attributeListener.enabled = true;
if (launchConfiguration.enableNotificationModule) config.modules.notification.enabled = true;

const runtime = new TestRuntime(config, {
setDefaultRepositoryAttributes: launchConfiguration.enableDefaultRepositoryAttributes ?? false
});
const runtime = new TestRuntime(
config,
{
setDefaultRepositoryAttributes: launchConfiguration.enableDefaultRepositoryAttributes ?? false
},
launchConfiguration.useCorrelator ? correlator : undefined
);
this.runtimes.push(runtime);

await runtime.init();
Expand Down
7 changes: 5 additions & 2 deletions packages/runtime/test/lib/TestRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ConsumptionConfig, ConsumptionController, GenericRequestItemProcessor }
import { ICoreAddress } from "@nmshd/core-types";
import { AccountController } from "@nmshd/transport";
import { ConsumptionServices, DataViewExpander, ModuleConfiguration, Runtime, RuntimeConfig, RuntimeHealth, RuntimeServices, TransportServices } from "../../src";
import { AbstractCorrelator } from "../../src/useCases/common/AbstractCorrelator";
import { MockEventBus } from "./MockEventBus";
import { TestNotificationItem, TestNotificationItemProcessor } from "./TestNotificationItem";
import { TestRequestItem } from "./TestRequestItem";
Expand All @@ -19,7 +20,8 @@ export class TestRuntime extends Runtime {

public constructor(
runtimeConfig: RuntimeConfig,
private readonly consumptionConfig: ConsumptionConfig
private readonly consumptionConfig: ConsumptionConfig,
correlator?: AbstractCorrelator
) {
super(
runtimeConfig,
Expand All @@ -43,7 +45,8 @@ export class TestRuntime extends Runtime {
}
}
}),
new MockEventBus()
new MockEventBus(),
correlator
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/test/misc/CorrelationId.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe("CorrelationId", function () {

beforeAll(async function () {
runtimeServiceProvider = new RuntimeServiceProvider();
runtime = (await runtimeServiceProvider.launch(1))[0];
runtime = (await runtimeServiceProvider.launch(1, { useCorrelator: true }))[0];

const accountController = Container.get(AccountController);
interceptor = new RequestInterceptor((accountController as any).synchronization.client);
Expand Down
2 changes: 1 addition & 1 deletion packages/transport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
"@nmshd/core-types": "*",
"@nmshd/crypto": "2.0.6",
"axios": "^1.7.7",
"correlation-id": "^5.2.0",
"fast-json-patch": "^3.1.1",
"form-data": "^4.0.0",
"https-proxy-agent": "^7.0.5",
Expand All @@ -95,6 +94,7 @@
"@types/luxon": "^3.4.2",
"@types/qs": "^6.9.16",
"@types/uuid": "^10.0.0",
"correlation-id": "^5.2.0",
"expect": "^29.7.0",
"ts-mockito": "^2.6.1"
},
Expand Down
8 changes: 8 additions & 0 deletions packages/transport/src/core/ICorrelator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface ICorrelator {
withId<R>(id: string, work: () => R): R;
withId<R>(work: () => R): R;
bindId<W extends Function>(id: string, work: W): W;
bindId<W extends Function>(work: W): W;
getId(): string | undefined;
setId(id: string): undefined;
}
4 changes: 3 additions & 1 deletion packages/transport/src/core/Transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SodiumWrapper } from "@nmshd/crypto";
import { AgentOptions } from "http";
import { AgentOptions as HTTPSAgentOptions } from "https";
import _ from "lodash";
import { ICorrelator } from "./ICorrelator";
import { TransportCoreErrors } from "./TransportCoreErrors";
import { TransportError } from "./TransportError";
import { TransportLoggerFactory } from "./TransportLoggerFactory";
Expand Down Expand Up @@ -85,7 +86,8 @@ export class Transport {
databaseConnection: IDatabaseConnection,
customConfig: IConfigOverwrite,
public readonly eventBus: EventBus,
loggerFactory: ILoggerFactory = new SimpleLoggerFactory()
loggerFactory: ILoggerFactory = new SimpleLoggerFactory(),
public readonly correlator?: ICorrelator
) {
this.databaseConnection = databaseConnection;
this._config = _.defaultsDeep({}, customConfig, Transport.defaultConfig);
Expand Down
15 changes: 11 additions & 4 deletions packages/transport/src/core/backbone/Authenticator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ILogger } from "@js-soft/logging-abstractions";
import { CoreDate } from "@nmshd/core-types";
import { AccountController } from "../../modules";
import { ICorrelator } from "../ICorrelator";
import { AuthClient } from "./AuthClient";
import { IRESTClientConfig } from "./RESTClient";
import { CredentialsBasic } from "./RESTClientAuthenticate";
Expand All @@ -11,8 +12,11 @@ export abstract class AbstractAuthenticator {
private token?: string;

private readonly authClient: AuthClient;
public constructor(private readonly config: IRESTClientConfig) {
this.authClient = new AuthClient(config);
public constructor(
private readonly config: IRESTClientConfig,
correlator?: ICorrelator
) {
this.authClient = new AuthClient(config, correlator);
}

public async getToken(): Promise<string> {
Expand Down Expand Up @@ -78,8 +82,11 @@ export abstract class AbstractAuthenticator {
}

export class Authenticator extends AbstractAuthenticator {
public constructor(private readonly accountController: AccountController) {
super(accountController.config);
public constructor(
private readonly accountController: AccountController,
correlator?: ICorrelator
) {
super(accountController.config, correlator);
}

public async getCredentials(): Promise<CredentialsBasic> {
Expand Down
17 changes: 11 additions & 6 deletions packages/transport/src/core/backbone/RESTClient.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ILogger } from "@js-soft/logging-abstractions";
import { CoreBuffer } from "@nmshd/crypto";
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
import correlator from "correlation-id";
import formDataLib from "form-data";
import { AgentOptions } from "http";
import { AgentOptions as HTTPSAgentOptions } from "https";
import _ from "lodash";
import { CoreIdHelper } from "../CoreIdHelper";
import { ICorrelator } from "../ICorrelator";
import { TransportLoggerFactory } from "../TransportLoggerFactory";
import { ClientResult } from "./ClientResult";
import { IPaginationDataSource, Paginator, PaginatorPercentageCallback } from "./Paginator";
Expand Down Expand Up @@ -66,6 +66,7 @@ export class RESTClient {

public constructor(
protected readonly config: IRESTClientConfig,
private readonly correlator?: ICorrelator,
requestConfig: AxiosRequestConfig = {}
) {
const defaults: AxiosRequestConfig = {
Expand Down Expand Up @@ -115,11 +116,15 @@ export class RESTClient {
this._logger = TransportLoggerFactory.getLogger(RESTClient);

this.axiosInstance = axios.create(resultingRequestConfig);
this.axiosInstance.interceptors.request.use((config) => {
const correlationId = correlator.getId();
config.headers["x-correlation-id"] = correlationId;
return config;
});

if (this.correlator) {
const correlator = this.correlator;
this.axiosInstance.interceptors.request.use((config) => {
const correlationId = correlator.getId();
config.headers["x-correlation-id"] = correlationId;
return config;
});
}

if (this.config.debug) {
this.addAxiosLoggingInterceptors(this.axiosInstance);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AxiosRequestConfig } from "axios";
import _ from "lodash";
import { ICorrelator } from "../ICorrelator";
import { AbstractAuthenticator } from "./Authenticator";
import { ClientResult } from "./ClientResult";
import { Paginator, PaginatorPercentageCallback } from "./Paginator";
Expand All @@ -15,9 +16,10 @@ export class RESTClientAuthenticate extends RESTClient {
public constructor(
config: IRESTClientConfig,
private readonly authenticator: AbstractAuthenticator,
correlator?: ICorrelator,
requestConfig: AxiosRequestConfig = {}
) {
super(config, requestConfig);
super(config, correlator, requestConfig);
}

private async runAuthenticated<T>(restCall: (token: string) => Promise<ClientResult<T>>) {
Expand Down
1 change: 1 addition & 0 deletions packages/transport/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from "./CoreSynchronizable";
export * from "./CoreUtil";
export * from "./DbCollectionName";
export * from "./DependencyOverrides";
export * from "./ICorrelator";
export * from "./Reference";
export * from "./Transport";
export * from "./TransportController";
Expand Down
Loading

0 comments on commit 7d482b5

Please sign in to comment.