Policy
Introduction
In event-driven architectures, policies act as intermediaries between events and commands. Similar to APIs, which handle client requests and convert them into commands, policies manage events from other services or external systems and convert them into commands. This process ensures that the system remains responsive and consistent across different services. Policies are especially useful when actions in one service should trigger changes in another. For example, if a user is deleted, any tasks assigned to that user should be closed automatically.
Implementation
The CloseTaskPolicy
class illustrates how to implement a policy within the Codebricks framework. It listens for specific events, processes them, and triggers the corresponding commands.
It can be found under: Task/src/useCases/write/CloseTask/application/CloseTaskPolicy.ts
import { Policy, ProcessMethods, OverwriteProtectionBody } from "@codebricks/codebricks-framework";
import { CloseTaskCommand } from "./CloseTaskCommand";
import { CloseTaskCommandHandler } from "./CloseTaskCommandHandler";
import { CloseTaskPolicyRepository } from "shared/infrastructure/consuming/policy/CloseTaskPolicyRepository";
import { UserDeletedEventMessage } from "shared/application/inboundEvents/UserDeletedEventMessage";
import { AssigneeIdValueObject } from "shared/domain/valueObjects/AssigneeIdValueObject";
export class CloseTaskPolicy extends Policy {
readonly useCaseName: string = 'CloseTask';
readonly processMethods: ProcessMethods = {
'Demo.User.UserDeleted': this.processDemoUserUserDeleted.bind(this)
};
readonly streamNames: string[] = ['Demo.User'];
constructor(readonly commandHandler: CloseTaskCommandHandler = new CloseTaskCommandHandler(), readonly repository: CloseTaskPolicyRepository = new CloseTaskPolicyRepository()) {
super(repository);
}
@OverwriteProtectionBody(false)
async processDemoUserUserDeleted(eventMessage: UserDeletedEventMessage): Promise<void> {
try {
const command: CloseTaskCommand = new CloseTaskCommand({
assigneeId: new AssigneeIdValueObject(eventMessage.aggregateId),
});
await this.commandHandler.handleCloseTask(command);
} catch (error) {
console.log(error);
}
}
}
Key Concepts
useCaseName
andstreamNames
Properties: These properties help identify the events that the policy listens for.processMethods
Property: Maps events to their respective processing methods.- Process Methods: Methods like
processDemoUserUserDeleted
handle specific events and generate commands based on the event data.
Best Practices
- Error Handling: Implement robust error handling to avoid silent failures in policy processing.
By default, all errors are caught and logged to ensure the processing of subsequent events continues. If you wish to stop processing upon encountering an error, modify the catch clause to handle that scenario.