UNPKG

@dolittle/sdk.events.handling

Version:

Dolittle is a decentralized, distributed, event-driven microservice platform built to harness the power of events.

155 lines (131 loc) 7.08 kB
// 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 { DateTime } from 'luxon'; import { IServiceProvider } from '@dolittle/sdk.dependencyinversion'; import { EventContext, IEventTypes, EventSourceId, EventType } from '@dolittle/sdk.events'; import { ExecutionContext } from '@dolittle/sdk.execution'; import { Internal, MissingEventInformation } from '@dolittle/sdk.events.processing'; import { Artifacts, ExecutionContexts, Guids } from '@dolittle/sdk.protobuf'; import { Cancellation } from '@dolittle/sdk.resilience'; import { IReverseCallClient, ReverseCallClient, reactiveDuplex } from '@dolittle/sdk.services'; import { EventHandlerRegistrationRequest, EventHandlerRegistrationResponse, EventHandlerClientToRuntimeMessage, EventHandlerRuntimeToClientMessage, HandleEventRequest, EventHandlerResponse } from '@dolittle/contracts/Runtime/Events.Processing/EventHandlers_pb'; import { Artifact } from '@dolittle/contracts/Artifacts/Artifact_pb'; import { Failure } from '@dolittle/contracts/Protobuf/Failure_pb'; import { EventHandlersClient } from '@dolittle/contracts/Runtime/Events.Processing/EventHandlers_grpc_pb'; import { RetryProcessingState, ProcessorFailure } from '@dolittle/contracts/Runtime/Events.Processing/Processors_pb'; import { EventHandlerId } from '../EventHandlerId'; import { IEventHandler } from '../IEventHandler'; /** * Represents an implementation of {@link Internal.EventProcessor} for {@link EventHandler}. */ export class EventHandlerProcessor extends Internal.EventProcessor<EventHandlerId, EventHandlersClient, EventHandlerRegistrationRequest, EventHandlerRegistrationResponse, HandleEventRequest, EventHandlerResponse> { /** * Initializes a new instance of {@link EventHandlerProcessor}. * @param {IEventHandler} _handler - The actual handler. * @param {IEventTypes} _eventTypes - Registered event types. */ constructor( private _handler: IEventHandler, private _eventTypes: IEventTypes ) { super('EventHandler', _handler.eventHandlerId); } /** @inheritdoc */ protected get registerArguments(): EventHandlerRegistrationRequest { const registerArguments = new EventHandlerRegistrationRequest(); registerArguments.setEventhandlerid(Guids.toProtobuf(this._identifier.value)); registerArguments.setScopeid(Guids.toProtobuf(this._handler.scopeId.value)); registerArguments.setPartitioned(this._handler.partitioned); if (this._handler.hasAlias) { registerArguments.setAlias(this._handler.alias!.value); } const handledArtifacts: Artifact[] = []; for (const eventType of this._handler.handledEvents) { handledArtifacts.push(Artifacts.toProtobuf(eventType)); } registerArguments.setEventtypesList(handledArtifacts); return registerArguments; } /** @inheritdoc */ protected createClient( client: EventHandlersClient, registerArguments: EventHandlerRegistrationRequest, callback: (request: HandleEventRequest, executionContext: ExecutionContext) => Promise<EventHandlerResponse>, executionContext: ExecutionContext, pingInterval: number, logger: Logger, cancellation: Cancellation): IReverseCallClient<EventHandlerRegistrationResponse> { return new ReverseCallClient<EventHandlerClientToRuntimeMessage, EventHandlerRuntimeToClientMessage, EventHandlerRegistrationRequest, EventHandlerRegistrationResponse, HandleEventRequest, EventHandlerResponse> ( (requests, cancellation) => reactiveDuplex(client, client.connect, requests, cancellation), EventHandlerClientToRuntimeMessage, (message, connectArguments) => message.setRegistrationrequest(connectArguments), (message) => message.getRegistrationresponse(), (message) => message.getHandlerequest(), (message, response) => message.setHandleresult(response), (connectArguments, context) => connectArguments.setCallcontext(context), (request) => request.getCallcontext(), (response, context) => response.setCallcontext(context), (message) => message.getPing(), (message, pong) => message.setPong(pong), executionContext, registerArguments, pingInterval, callback, cancellation, logger ); } /** @inheritdoc */ protected getFailureFromRegisterResponse(response: EventHandlerRegistrationResponse): Failure | undefined { return response.getFailure(); } /** @inheritdoc */ protected getRetryProcessingStateFromRequest(request: HandleEventRequest): RetryProcessingState | undefined { return request.getRetryprocessingstate(); } /** @inheritdoc */ protected createResponseFromFailure(failure: ProcessorFailure): EventHandlerResponse { const response = new EventHandlerResponse(); response.setFailure(failure); return response; } /** @inheritdoc */ protected async handle(request: HandleEventRequest, executionContext: ExecutionContext, services: IServiceProvider, logger: Logger): Promise<EventHandlerResponse> { if (!request.getEvent() || !request.getEvent()?.getEvent()) { throw new MissingEventInformation('no event in HandleEventRequest'); } const pbEvent = request.getEvent()!.getEvent()!; const pbSequenceNumber = pbEvent.getEventlogsequencenumber(); if (pbSequenceNumber === undefined) throw new MissingEventInformation('Sequence Number'); const pbEventSourceId = pbEvent.getEventsourceid(); if (!pbEventSourceId) throw new MissingEventInformation('EventSourceId'); const pbExecutionContext = pbEvent.getExecutioncontext(); if (!pbExecutionContext) throw new MissingEventInformation('Execution context'); const pbOccurred = pbEvent.getOccurred(); if (!pbOccurred) throw new MissingEventInformation('Occurred'); const pbEventType = pbEvent.getEventtype(); if (!pbEventType) throw new MissingEventInformation('Event Type'); const eventContext = new EventContext( pbSequenceNumber, EventSourceId.from(pbEventSourceId), DateTime.fromJSDate(pbOccurred.toDate()), ExecutionContexts.toSDK(pbExecutionContext), executionContext); let event = JSON.parse(pbEvent.getContent()); const eventType = Artifacts.toSDK(pbEventType, EventType.from); if (this._eventTypes.hasTypeFor(eventType)) { const typeOfEvent = this._eventTypes.getTypeFor(eventType); event = Object.assign(new typeOfEvent(), event); } await this._handler.handle(event, eventType, eventContext, services, logger); return new EventHandlerResponse(); } }