Transactional Inbox/Outbox pattern for Durable Objects

Overview

do-transactional-outbox

One of the challenges that many event-driven systems face is the fact that they have to write to the database and send out an event about it. But it is impossible (or at least very impractical) to have a database-like transaction span both a database and some sort of message bus.

The Transactional Outbox pattern is one way to solve this problem. By saving both the state and a message to the same database, we can use regular database transaction semantics, and we can then check the database to see if any messages need to be sent. And to retry sending them in the case of failures.

Installation

The usual npm install do-transaction-outbox or yarn add do-transactional-outbox should do the trick

Usage

If you wrap the export of your Durable Object with a withTransactionalOutbox(), a OutboxManager will automatically be added to your env Object under the key OUTBOX_MANAGER.

The OutboxManager has a put method with exactly the same signatures as the DurableObjectStorage one, except with one extra argument, which is the message to be send.

To actually send the messages you define an extra method on your Durable Object sendMessages(messages: { id: string; msg: any }[]): Promise<void>

A full example:

import { OutboxManager, TOB_DurableObject, withTransactionalOutbox } from 'do-transactional-outbox'

export interface Env {
  TEST_DO_TOB: DurableObjectNamespace
  OUTBOX_MANAGER: OutboxManager
}

class DO implements TOB_DurableObject {
  private storage: DurableObjectStorage
  constructor(state: DurableObjectState, protected readonly env: Env) {
    this.storage = state.storage
  }

  async sendMessages(messages: { id: string; msg: any }[]): Promise<void> {
    Object.entries(messages).forEach(async ([key, msg]) => {
      await this.storage.put(`__msg::${key}`, msg)
    })
  }
  
  async fetch(request: Request): Promise<Response> {
    const storage = this.env.OUTBOX_MANAGER
    await storage.put(`one`, 'first', 'first')
    const puts = {
      two: 'second',
      three: 'third',
    }
    await storage.put(puts, { type: 'multiples', blah: true })
    return new Response('Ok', { status: 200 })
  }
}

const exportedDO = withTransactionalOutbox(TestDO)

export { exportedDO }
You might also like...

An algorithm for fast 2D pattern-matching with wildcards.

An algorithm for fast 2D pattern-matching with wildcards.

pattern-match-2d.js An algorithm for fast 2D pattern-matching with wildcards, with a demo app inspired by MarkovJunior (by Maxim Gumin). The algorithm

Nov 5, 2022

A probabilistic programming language based on pattern-rewriting

A probabilistic programming language based on pattern-rewriting

MJr-compiler MJr is a probabilistic programming language based on pattern-rewriting, heavily inspired by MarkovJunior by Maxim Gumin. This project pro

Dec 15, 2022

A utility package to help implement stateless CSRF protection using the Double Submit Cookie Pattern in express.

Double CSRF A utility package to help implement stateless CSRF protection using the Double Submit Cookie Pattern in express. Dos and Don'ts • Getting

Dec 28, 2022

Json-parser - A parser for json-objects without dependencies

Json Parser This is a experimental tool that I create for educational purposes, it's based in the jq works With this tool you can parse json-like stri

Jan 3, 2022

Hierarchical Converter for Array of Objects

Conversor Hierárquico para Array de Objetos - Hierarchical Converter to Array of Objects Docker-compose Cria a interface network e containers indicado

Jan 27, 2022

Visualize the Directed Acyclic Graph that Git creates to connect Commit, Tree and Blob objects internally.

Visualize the Directed Acyclic Graph that Git creates to connect Commit, Tree and Blob objects internally.

Git Graph Visualize the Directed Acyclic Graph that Git creates to connect Commit, Tree and Blob objects. Hosted at HarshKapadia2.github.io/git-graph.

Aug 21, 2022

Binary-encoded serialization of JavaScript objects with generator-based parser and serializer

YaBSON Schemaless binary-encoded serialization of JavaScript objects with generator-based parser and serializer This library is designed to transfer l

Aug 9, 2022

An API for producing and validating ActivityPub objects.

ActivityHelper A library that exports an API for producing and validating ActivityPub objects. In a federated system bound together by protocols, it's

May 2, 2022
Owner
Erwin van der Koogh
PM at @cloudflare
Erwin van der Koogh
A rate-limiter using Durable Objects on CF Workers that actually doesn't rate limit anything.

Rate Limiter - built for Cloudflare Workers, using Durable Objects Features Supports fixed or sliding window algorithms Scoped rate-limiting Caching C

Ian 11 Dec 15, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Horizontally scalable blockchain using STARK's and partitioned transactional memory

quark quark - quick STARK! A decentralized horizontally-scaled state machine that can transfer 1,000,000 unique tokens on Uniswap in a single atomic t

Liam Zebedee 56 Nov 25, 2022
Cypress commands are asynchronous. It's a common pattern to use a then callback to get the value of a cypress command

cypress-thenify Rationale Cypress commands are asynchronous. It's a common pattern to use a then callback to get the value of a cypress command. Howev

Mikhail Bolotov 15 Oct 2, 2022
Implementação do Observer Pattern em TypeScript para o Código Fonte TV

Observer - Design Pattern Exemplos de implementação do Design Pattern Observer, descrito no livro Design Patterns: Elements of Reusable Object-Oriente

Gabriel Froes 11 Nov 30, 2022
Ethereum smart contract gas cost waste pattern detection and patching tool

Ethereum smart contract gas cost waste pattern detection and patching tool

ibelab 4 Mar 23, 2022
Rename image after pasting, support name pattern and auto renaming.

Obsidian paste image rename This plugin is inspired by Zettlr, Zettlr shows a prompt that allows the user to rename the image, this is a great help if

Xiao Meng 82 Jan 2, 2023
Connect your Ethereum smart contract to any real world API using the oracle pattern!

Minimal Viable Oracle (MVO) - An effective way to Build your own oracle with Solidity Smart contracts cannot access off-chain data directly. This repo

Noah 9 Aug 25, 2022