Socket
Socket
Sign inDemoInstall

@halcyon-agile/node-event-sourcing

Package Overview
Dependencies
3
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @halcyon-agile/node-event-sourcing

> Opinionated OOP based node.js event sourcing library inspired by laravel-event-sourcing


Version published
Weekly downloads
12
decreased by-69.23%
Maintainers
1
Created
Weekly downloads
 

Readme

Source

NODE EVENT SOURCING

Opinionated OOP based node.js event sourcing library inspired by laravel-event-sourcing

Features

  • Reliable event publisher
  • Built for microservices
  • CQRS
  • Dead letter queue support

Current Limitations

  • Currently supports only DynamoDB as Event Store
  • Currently supports only Kafka as Message Broker

Requirements

  • Kafka
  • DynamoDB

Concepts

AggregateRoot

Class that handles the business logic and stream of events of a specific item such as a single Product and Order.

  • Events are created via AggregateRoot.createEvent method
  • Events created are automatically published into Kafka topic via DynamoDB Stream (Production) or Polling (Dev)

Listener

Class that handles event after being fired

Projector

Class that handles the update to read table after event is fired

Getting Started

Configuration

process.env.KAFKA_BROKERS = "localhost:9092,localhost:9093"; // default: localhost:9092
process.env.KAFKA_GROUP_ID = "group"; // default: example-group

Creating Event

interface Item {
  productId: string | null;
  quantity: number;
}

export default class CartItemAdded {
  event = "CartItemAdded";

  payload: Item = {
    productId: null,
    quantity: 0,
  };

  constructor(payload: Item) {
    this.payload = payload;
  }
}

Creating AggregateRoot

import { AggregateRoot } from "@halcyon-agile/node-event-sourcing";
import CartItemAdded from "./Events/CartItemAdded";

interface Item {
  productId: string;
  quantity: number;
}

export default class CartAggregateRoot extends AggregateRoot {
  public items: Item[] = [];
  public snapshotIn = 0;

  constructor() {
    super();
  }

  public async addItemToCart(item: Item): Promise<void> {
    await this.createEvent(new CartItemAdded(item));
  }

  public async applyCartItemAdded(item: Item): Promise<void> {
    const existingItem = this.items.find((i) => i.productId === item.productId);

    if (existingItem) {
      existingItem.quantity = existingItem.quantity + item.quantity;
    } else {
      this.items.push(item);
    }
  }

  public async applySnapshot(currentState: { items: Item[] }): Promise<void> {
    this.items = currentState.items;
  }
}

Creating Event Listener

import { Listener } from "@halcyon-agile/node-event-sourcing";

export default CartItemAddedListener implements Listener {
  public async handle() {
    // ...
  }
}

Creating Projections

import { Projector } from "@halcyon-agile/node-event-sourcing";

export default class HotProductsProjector implements Projector {
  public async onCartItemAdded() {
    // ...
  }
}

Running Event Listener

import { Runner } from "@halcyon-agile/node-event-sourcing";
import * as path from "path";

Runner.registerListeners([path.resolve("./Listeners/CartListener")]);
Runner.registerProjectors([path.resolve("./Projectors/HotProductsProjector")]);

Runner.run()
  .then(() => {
    console.log("Event Sourcing is running...");
  })
  .catch((error) => {
    console.log(error.message);
  });

Running the Event Publisher

Development

poll-publisher.js
const Publisher = require("@halcyon-agile/node-event-sourcing/Publisher");

Publisher.run();
node poll-publisher.js

Production

Upload the @halcyon-agile/node-event-sourcing/lambda-event-publisher.zip in AWS Lambda and use that lambda function as a DynamoDB stream source. Make sure that the Lambda connects to Kafka server.

Handling failures

Dead letter queue
Circuit breaker
Distributed circuit breaker

Handling transient failures

Immediate retry
Exponential Backoff

What does the business say about the failure?

If you can make it fail fast, do it instead of using exponential backoff or dead letter queues.

Replaying Events

replay-events.js

const Replay = require("@halcyon-agile/node-event-sourcing/ReplayEvents");

// Replay all events and use all existing projectors
Replay.run();

// Replay specific projectors and event
Replay.run(
  [path.resolve("./Projectors/HotProductsProjector")],
  ["CartItemAdded"]
);
node replay-events.js
node

FAQs

Last updated on 13 Dec 2021

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc