@dolittle/sdk.resources
Version:
Dolittle is a decentralized, distributed, event-driven microservice platform built to harness the power of events.
96 lines (80 loc) • 4.83 kB
text/typescript
// Copyright (c) Dolittle. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
import { Logger } from 'winston';
import { ExecutionContext, TenantId } from '@dolittle/sdk.execution';
import { ExecutionContexts } from '@dolittle/sdk.protobuf';
import { Cancellation } from '@dolittle/sdk.resilience';
import { reactiveUnary, UnaryMethod } from '@dolittle/sdk.services';
import { Failure } from '@dolittle/contracts/Protobuf/Failure_pb';
import { CallRequestContext } from '@dolittle/contracts/Services/CallContext_pb';
import { ResourcesClient } from '@dolittle/contracts/Runtime/Resources/Resources_grpc_pb';
import { FailedToGetResourceForTenant } from '../FailedToGetResourceForTenant';
import { ResourceName } from '../ResourceName';
/**
* Represents a system that can create resources by fetching configuration from the Runtime.
* @template TResource - The type of the resource.
* @template TRequest - The type of the resource configuration request.
* @template TResponse - The type of the resource configuration response.
*/
export abstract class ResourceCreator<TResource, TRequest, TResponse> {
/**
* Initialises a new instance of the {@link ResourceCreator} class.
* @param {ResourceName} _resource - The name of the resource type.
* @param {UnaryMethod} _method - The gRPC method to call to get the resource configuration from the Runtime.
* @param {ResourcesClient} _client - The resources client to make requests to the Runtime with.
* @param {ExecutionContext} _executionContext - The base execution context for the client.
* @param {Logger} _logger - The logger to use for logging.
*/
protected constructor(
private readonly _resource: ResourceName,
private readonly _method: UnaryMethod<TRequest, TResponse>,
private readonly _client: ResourcesClient,
private readonly _executionContext: ExecutionContext,
private readonly _logger: Logger,
) {}
/**
* Creates the resource for the provided tenant by fetching configuration from the Runtime.
* @param {TenantId} tenant - The tenant id to create the resource for.
* @param {Cancellation} cancellation - An optional cancellation to cancel the operation.
* @returns {Promise} - A {@link Promise} that, when resolved, returns the created resource.
*/
async createFor(tenant: TenantId, cancellation: Cancellation = Cancellation.default): Promise<TResource> {
try {
this._logger.debug(`Getting ${this._resource} resource for tenant ${tenant}`);
const executionContext = this._executionContext.forTenant(tenant);
const callContext = ExecutionContexts.toCallContext(executionContext);
const request = this.createResourceRequest(callContext);
const response = await reactiveUnary(this._client, this._method, request, cancellation).toPromise();
const [requestFailed, requestFailure] = this.requestFailed(response);
if (requestFailed) {
this._logger.warn(`Failed getting ${this._resource} resource for tenant ${tenant} because ${requestFailure!.getReason()}`);
throw new FailedToGetResourceForTenant(this._resource, tenant, requestFailure!.getReason());
}
return await this.createResourceFrom(response);
} catch (error) {
if (error instanceof FailedToGetResourceForTenant) {
throw error;
}
this._logger.warn(`Failed getting ${this._resource} resource for tenant ${tenant}}`, error);
throw new FailedToGetResourceForTenant(this._resource, tenant, error as any);
}
}
/**
* Creates a request to get the resource configuration using the provided call context.
* @param {CallRequestContext} callContext - The call context to use for the request containing the tenant id.
* @returns {TRequest} A new request.
*/
protected abstract createResourceRequest(callContext: CallRequestContext): TRequest;
/**
* Checks whether the request failed based on the response.
* @param {TResponse} response - The response received from the Runtime.
* @returns {[false] | [true, Failure]} False if the request succeeded, true and the failure if it failed.
*/
protected abstract requestFailed(response: TResponse): [false] | [true, Failure];
/**
* Creates the resource from the configuration received from the Runtime.
* @param {TResponse} response - The response received from the Runtime.
* @returns {Promise<TResource>} - A {@link Promise} that, when resolved, returns the created resource.
*/
protected abstract createResourceFrom(response: TResponse): Promise<TResource>;
}