<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/batching-the-billing-ledger-but-with-less--ehwro9yj6" -->

---
title: Batching the billing ledger (but with less) | daily.dev
description: A Ruby developer built 'bab', a single-process alternative to a Kafka-plus-DuckDB billing ledger pipeline described by Vicente in an earlier article. It uses...
canonical: https://daily.dev/posts/batching-the-billing-ledger-but-with-less--ehwro9yj6
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Batching the billing ledger (but with less) | daily.dev
og:description: A Ruby developer built 'bab', a single-process alternative to a Kafka-plus-DuckDB billing ledger pipeline described by Vicente in an earlier article. It uses...
og:url: https://daily.dev/posts/batching-the-billing-ledger-but-with-less--ehwro9yj6
og:image: https://api.daily.dev/og/posts/eHWRo9Yj6.png
og:image:alt: Batching the billing ledger (but with less)
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Batching the billing ledger (but with less)

**[RUBYLAND](https://daily.dev/sources/rubyla)** · 29 min read · 0 upvotes · 0 comments

## Summary

A Ruby developer built 'bab', a single-process alternative to a Kafka-plus-DuckDB billing ledger pipeline described by Vicente in an earlier article. It uses new Ruby libraries herringbone (Parquet) and protostar (protobuf), plus a Ractor-native web server called kino, to ingest billing events without Kafka, DuckDB or google-protobuf. On a laptop it handled 80K events per second with no rejected requests, writing Parquet files at 21.2 bytes per event versus 22.1 with DuckDB. A priced AWS setup for 10K events per second with 30 days retention comes to about $641 a month on two VMs, or $396 a month using Firehose instead of a load balancer and second VM.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://blog.julik.nl/2026/10/batching-with-less>

## Questions this post answers

### How fast can a Ruby app using Ractors ingest events without Kafka?

A Ruby-native billing ledger system built with Ractors, a Rust-based web server called kino, and the herringbone Parquet library handled 80,000 events per second on a laptop with no rejected requests. At 10,000 events per second it showed a p99 latency of 2.6ms with 50 events per request, and 0.17ms p50 with one event per request and 10,000 fsyncs per second.

_Anyone weighing Ractors against Kafka for event ingestion can track real-world benchmarks like this on daily.dev._

### What does it cost to run a 10,000 events per second billing pipeline on AWS for a month?

A two-VM setup using c8gd.2xlarge instances, a Network Load Balancer, and S3 with same-region replication costs about $641 a month for 10,000 events per second with 30 days of retention. Replacing the load balancer and second VM with Amazon Data Firehose (at 50 events per record) drops the total to about $396 a month, roughly 2.5 cents per million events in the first setup.

_Teams budgeting event-ingestion infrastructure can compare cost breakdowns like this on daily.dev before committing._

### How can I avoid using google-protobuf and DuckDB in a Ruby billing pipeline?

A pure-Ruby alternative stack replaces google-protobuf with a library called protostar and DuckDB-based Parquet writing with a library called herringbone, both of which are Ractor-safe and avoid native C++ dependencies. Herringbone is about a 240KB pure-Ruby download, and protostar installs as a drop-in replacement for google-protobuf via Bundler 4.1's override feature.

_Ruby developers avoiding heavyweight native dependencies can find alternatives like these surfaced on daily.dev._

## Similar posts on daily.dev

- [30\+ Updates per Second per Account: Uber Scales Ledger Processing with Batching](https://daily.dev/posts/30-updates-per-second-per-account-uber-scales-ledger-processing-with-batching-h5w2zvquh) · InfoQ · 0 upvotes · 0 comments
- [Feed your data lake with AI-ready tables for 30-50% lower cost](https://daily.dev/posts/feed-your-data-lake-with-ai-ready-tables-for-30-50-lower-cost-mpdjf1hfv) · Confluent Blog · 0 upvotes · 0 comments
- [How We Built a Real-Time Stock Pricing System at Scale](https://daily.dev/posts/how-we-built-a-real-time-stock-pricing-system-at-scale-enzk8krjp) · ITNEXT · 20 upvotes · 0 comments
- [AWS-Native Analytics vs. Tinybird: Cost and Latency Compared](https://daily.dev/posts/aws-native-analytics-vs-tinybird-cost-and-latency-compared-qfbbkwure) · AWS Fundamentals · 4 upvotes · 0 comments

---

Tags: [#aws](https://daily.dev/tags/aws), [#ruby](https://daily.dev/tags/ruby), [#big-data](https://daily.dev/tags/big-data), [#kafka](https://daily.dev/tags/kafka)

[View this post on daily.dev](https://daily.dev/posts/batching-the-billing-ledger-but-with-less--ehwro9yj6)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Batching the billing ledger (but with less)","url":"https://daily.dev/posts/batching-the-billing-ledger-but-with-less--ehwro9yj6","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/batching-the-billing-ledger-but-with-less--ehwro9yj6"},"datePublished":"2026-10-31T14:30:18.664Z","dateModified":"2026-10-31T14:30:53.981Z","description":"A Ruby developer built 'bab', a single-process alternative to a Kafka-plus-DuckDB billing ledger pipeline described by Vicente in an earlier article. It uses...","image":"https://media.daily.dev/image/upload/s--1KxV4ohY--/f_auto/v1722860400/public/Placeholder%2007","thumbnailUrl":"https://media.daily.dev/image/upload/s--1KxV4ohY--/f_auto/v1722860400/public/Placeholder%2007","isAccessibleForFree":true,"articleSection":"RUBYLAND","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"RUBYLAND","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/rubyla","url":"https://daily.dev/sources/rubyla"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/batching-the-billing-ledger-but-with-less--ehwro9yj6","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"aws,ruby,big-data,kafka","timeRequired":"PT29M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"RUBYLAND","item":"https://daily.dev/sources/rubyla"},{"@type":"ListItem","position":3,"name":"Batching the billing ledger (but with less)"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/batching-the-billing-ledger-but-with-less--ehwro9yj6#faq","mainEntity":[{"@type":"Question","name":"How fast can a Ruby app using Ractors ingest events without Kafka?","acceptedAnswer":{"@type":"Answer","text":"A Ruby-native billing ledger system built with Ractors, a Rust-based web server called kino, and the herringbone Parquet library handled 80,000 events per second on a laptop with no rejected requests. At 10,000 events per second it showed a p99 latency of 2.6ms with 50 events per request, and 0.17ms p50 with one event per request and 10,000 fsyncs per second. Anyone weighing Ractors against Kafka for event ingestion can track real-world benchmarks like this on daily.dev."}},{"@type":"Question","name":"What does it cost to run a 10,000 events per second billing pipeline on AWS for a month?","acceptedAnswer":{"@type":"Answer","text":"A two-VM setup using c8gd.2xlarge instances, a Network Load Balancer, and S3 with same-region replication costs about $641 a month for 10,000 events per second with 30 days of retention. Replacing the load balancer and second VM with Amazon Data Firehose (at 50 events per record) drops the total to about $396 a month, roughly 2.5 cents per million events in the first setup. Teams budgeting event-ingestion infrastructure can compare cost breakdowns like this on daily.dev before committing."}},{"@type":"Question","name":"How can I avoid using google-protobuf and DuckDB in a Ruby billing pipeline?","acceptedAnswer":{"@type":"Answer","text":"A pure-Ruby alternative stack replaces google-protobuf with a library called protostar and DuckDB-based Parquet writing with a library called herringbone, both of which are Ractor-safe and avoid native C++ dependencies. Herringbone is about a 240KB pure-Ruby download, and protostar installs as a drop-in replacement for google-protobuf via Bundler 4.1's override feature. Ruby developers avoiding heavyweight native dependencies can find alternatives like these surfaced on daily.dev."}}]}
```

