{"id":21298366,"url":"https://github.com/yornaath/service-outbox","last_synced_at":"2026-02-13T23:34:31.731Z","repository":{"id":51695887,"uuid":"216177727","full_name":"yornaath/service-outbox","owner":"yornaath","description":"Transactional outbox pattern for node and mongodb","archived":false,"fork":false,"pushed_at":"2022-12-30T18:53:54.000Z","size":49,"stargazers_count":19,"open_issues_count":4,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-06T07:24:19.769Z","etag":null,"topics":["events","libra","microservice","mongodb","nodejs","transactional-outbox","typesc"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yornaath.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-19T09:01:11.000Z","updated_at":"2024-11-18T08:12:01.000Z","dependencies_parsed_at":"2023-01-31T13:30:49.941Z","dependency_job_id":null,"html_url":"https://github.com/yornaath/service-outbox","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/yornaath/service-outbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yornaath%2Fservice-outbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yornaath%2Fservice-outbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yornaath%2Fservice-outbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yornaath%2Fservice-outbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yornaath","download_url":"https://codeload.github.com/yornaath/service-outbox/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yornaath%2Fservice-outbox/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264870673,"owners_count":23676287,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["events","libra","microservice","mongodb","nodejs","transactional-outbox","typesc"],"created_at":"2024-11-21T14:51:12.491Z","updated_at":"2026-02-13T23:34:26.699Z","avatar_url":"https://github.com/yornaath.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# service-outbox\n\nA module that uses mongodb and creates a tailable capped collection for publishing events for a microservice.\n\nIt can be tailed and has schema validation.\n\nIt also ha support for using a session with a transaction to ensure atomicity in modifying state and publishing an event.\n\n### Inspired by\n\nTalks and papers by Chris Richardson\n\n[Using sagas to maintain data consistency in a microservice architecture by Chris Richardson](https://www.youtube.com/watch?v=YPbGW3Fnmbc)\n\n[Pattern: Transactional outbox](https://microservices.io/patterns/data/transactional-outbox.html)\n\n## Real world example\n\n```typescript\nimport { ServiceOutbox } from \"@piing/service-outbox\"\nimport Order from \"./models/Order\"\n\n\n// Defining the types of messages this service can publish.\n\ntype OrderCreatedMessage = {\n  type: \"order_created\"\n  data: {\n    ordernr: number\n  }\n}\n\ntype OrderCompletedMessage = {\n  type: \"order_completed\"\n  data: {\n    ordernr: number\n  }\n}\n\ntype Message = OrderCreatedMessage | OrderCompletedMessage\n\n// Defining the outbox has strong typing and mongoose schema validation.\n// Key is the type of message and the object associated is a mongoose.Schema\n// Challenge is keeping the types and Schema in sync\n\nconst outbox = new ServiceOutbox\u003cMessage\u003e(\"OrderServiceOutbox\",{\n  \"order_created\": {\n    data: {\n      ordernr: {\n        type: Number,\n        required: true\n      }\n    }\n  },\n  \"order_completed\": {\n    data: {\n      ordernr: {\n        type: Number,\n        required: true\n      }\n    }\n  }\n})\n\n// Atomic operation.\n// Creating order and creating the outbox message is done in the same transaction.\n\nconst makeOrder = async() =\u003e {\n  const session = await mongoose.startSession()\n\n  session.startTransaction()\n\n  const order = await Order.create(..., { session })\n\n  await outbox.put({\n    type: \"order_created\",\n    data: {\n      ordernr: order.nr\n    }\n  }), session)\n\n  await session.commitTransaction()\n\n  return order\n}\n\n// Tailing the outbox uses @most/core Streams\n// In this example we push the message to kafka.\n// We also make sure we that we only publish new events on service restart\n// by tracking the cursor of latest published event\n\nconst worker = async() =\u003e {\n\n  const cursor: Date = await getLatestPublishedServiceCreatedDate()\n\n  const [outbox$, scheduler, close] = outbox.tail(cursor)\n\n  const published$ = tap(async (orderServiceMessage) =\u003e {\n    await publishToKafka(\"orders\", orderServiceMessage.type, orderServiceMessage.data)\n      // Note: if the server where to crash here, its a chance the message can be sent twice.\n      // But that is a better option than loosing a message\n    await setLatestPublishedServiceCreatedDate(orderServiceMessage.created)\n  }, outbox$,)\n\n  runEffects(published$, scheduler)\n\n}\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyornaath%2Fservice-outbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyornaath%2Fservice-outbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyornaath%2Fservice-outbox/lists"}