acco

acco

Sequin - Elixir and Postgres for a feature-rich message queue

Hey everyone,

Excited to share a new open-source project built with Elixir. Sequin combines Elixir and Postgres into a feature-rich message queue.

We (the maintainers) were searching for the goldilocks message stream/queue. Kafka’s great when you need tremendous scale, but the trade-off is that it has few features and is hard to debug/configure/operate. SQS also has limited features, and we don’t like the dev/test story. RabbitMQ was closest to what we were seeking, but was the most unfamiliar to the team, and looked like it would be a black box.

Databases and messaging systems are at the heart of most applications. But having both adds complexity. We already know and love Postgres – can’t it do both?

Teams pass on using Postgres for streaming/queuing use cases for two primary reasons:

  1. They underestimate Postgres’ ability to scale to their requirements/needs
  2. Building a stream/queue on Postgres is DIY/open-ended

Getting DIY right requires some diligence to build a performant system that doesn’t drop messages (MVCC can work against you). We also wanted a ton of features from other streams/queues that weren’t available off-the-shelf, namely:

  • message routing with subjects
  • a CLI with observability
  • webhook and WAL ingestion (more on that in a bit)

So, we built something that leans into Postgres’ strengths. We love the stream-based model, where messages persist in one or more streams. Each of those streams have their own retention policies (like Kafka). And then you can create consumers that process a subset of messages based on filters exactly-once.

We didn’t like the idea of a Postgres extension. We wanted something we could use with any existing hosted Postgres database. And the Elixir layer gives us a lot of performance benefits. We use Elixir to do stuff that Postgres is bad at, like cache and keep counters.

Plus, who doesn’t want to build in Elixir as much as they can :slight_smile:

Because it’s all Just Postgres™, observability comes out-of-the-box. But we love a good CLI, so we’ve already built out a lot there to make debugging/observing easy (sequin observe is like htop for your messages).

We think killer use-cases for a Postgres-based stream are (1) processing Postgres WAL data and (2) ingesting webhooks.

For (1), we built on the shoulders of giants (h/t Postgrex, Realtime, Cainophile). It’s really neat to be able to process the WAL as a message queue!

For (2), we’re planning a way to expose HTTP endpoints so you can go from API → Sequin endpoint → Postgres → your app.

Under the hood, Sequin uses a very simple and familiar schema for the stream. We tried a lot of fancy stuff, but the simplest route turned out to be the most performant.

Messages flow into the messages table (partitioned by the stream_id). In the same transaction, messages are fanned out to each consumer that’s filtering for that message (consumer_messages).

In terms of performance, this means Sequin can ingest messages about as fast as Postgres can insert them. On the read side, consuming messages involves “claiming” rows in consumer_messages by marking them as delivered, then later deleting those rows on ack.

We benched on a db.m5.xlarge (4-core, 16GB RAM, $260/mo) RDS instance and the system was happy at 5k messages/sec, bursting up to 10k messages/sec. Your laptop is beefier than this, obviously bigger machines can do more.

We still have a lot to build. It’s pre-1.0. And we’re curious if the model of “combine a stateless docker container (Elixir) with your existing Postgres db” will resonate with people.

You can see an example of using Sequin with Broadway here:

https://github.com/sequinstream/sequin/tree/main/examples/elixir_broadway

We’re looking forward to feedback and are happy to shape the roadmap according to your real-world needs! Leave a comment or send me a DM if there’s anything you’d like to see

https://github.com/sequinstream/sequin

Most Liked Responses

acco

acco

Hey everyone –

A few months ago, we announced Sequin, an open-source project that combined Elixir and Postgres for message queuing. Since then, we’ve made a big pivot in our focus, and I’m excited to share where we’re headed.

https://github.com/sequinstream/sequin

v0.6 – CDC

While we started with a broader focus of being a full-featured message queue, we’ve learned the real challenge is Change Data Capture (CDC). That’s what we’re focusing on now: Sequin is a lightweight, Elixir-powered alternative to Debezium.

With Sequin, you can stream Postgres rows and changes to message queues like SQS or GCP Pub/Sub and streams like Kafka. You can start with a backfill of current data in your Postgres table(s), then continue to stream changes in real-time.

If you don’t have a queue/stream, we also support webhook destinations and offer our own native stream, Sequin Stream. Both guarantee exactly-once processing.

Why the change?

Most of our early users came to us specifically for our WAL processing capabilities – they already had their data in Postgres and needed a reliable way to capture changes.

While tools like Debezium exist for this use case, they’re complex to set up and maintain. Debezium requires Kafka and has limited tooling for monitoring and debugging. By focusing solely on Postgres, we’ve built a simpler solution that can match Debezium’s performance without the operational overhead.

What’s new in v0.6?

  • We’ve refined our core CDC functionality and now support native destinations for message queues and streams.

  • We’ve introduced sequin.yaml for declarative configuration (think lightweight Terraform).

  • Added “Change Retention” which uses a Postgres table to retain WAL changes for a period of time. This lets you replay changes to a destination, which is super useful for debugging or error recovery.

  • Added “backfills” for streaming data already in a Postgres table to a destination.

  • Improved our own native stream, Sequin Stream. It has a HTTP-based consume interface a lot like SQS, but it’s Postgres-based.

  • Improved support for very large transactions, large rows, and TOAST columns.

  • Various performance and stability improvements.

How it works

We’re still building on the same foundation:

  • Elixir implementation (no Postgres extensions needed)

  • Works with any hosted Postgres database

  • Web console and CLI

  • Exactly-once processing guarantees

(The web console is actually LiveView + LiveSvelte, which we’ve written about here.)

Looking forward

Upcoming features we’re most excited about are transforms (write your own in Elixir/JS) and joins (combine multiple tables into one object).

Try It Out

If you’re looking for a lightweight, Elixir-native way to handle CDC from Postgres, try Sequin.

Check out the repo: GitHub - sequinstream/sequin: Postgres change data capture to streams, queues, and search indexes like Kafka, SQS, Elasticsearch, HTTP endpoints, and more · GitHub

Check out one of our quickstarts: Get started with webhooks - Sequin

Or, try it out in the cloud: https://console.sequinstream.com/

We’re excited about this new direction and would love your feedback. Whether you’re using CDC today, have used Debezium in the past, or are just exploring CDC, your thoughts and requirements are invaluable for us to hear. Feel free to comment here or send a DM.

17
Post #9
acco

acco

Hey everyone,

Wanted to share all the updates we’ve made to Sequin.

We made a significant overhaul to Sequin in v0.4. Before, you’d push messages to Sequin streams via HTTP. Streams were persisted in Sequin-managed Postgres tables.

As of v0.4, Sequin instead streams your existing Postgres tables.

You can use Sequin to add streaming capabilities to existing data, like you might with a Debezium + Kafka pipeline. Or you can create new tables that you’ll use specifically to power streaming use cases as a pure Kafka alternative.

After connecting a Postgres table to Sequin, you can setup consumers for that table. A consumer can start at any “position” in the table: the beginning, at a specific row, or at the end. If it’s a push consumer, Sequin will push changes to your application via HTTP POST. If it’s a pull consumer, Sequin will provision a new HTTP endpoint that your application’s workers will use to pull messages.

You can have 1 or 1000 workers subscribe to a consumer. And you get guarantees like exactly-once processing of all rows and changes.

So, a table in Sequin is like a topic in Kafka. A consumer is like a Kafka consumer group. And instead of offsets, consumers traverse tables using a sorted column on your table.

Like Kafka, Sequin also delivers changes FIFO. So if a Postgres row changes multiple times in quick succession, each change will only be delivered after the prior change was acknowledged, avoiding race conditions.

So you can think of Sequin as an Elixir app that sits on top of your Postgres database and does 3 things:

  1. Safely paginates and detects changes to your Postgres tables.

  2. Manages consumer state (FIFO, fan-out, delivery, etc).

  3. Offers a control and observability plane on top of all this.

Our bet is that for many (most?) teams and use cases, a Postgres table is a better storage layer than Kafka. You’re already operating Postgres. And data in Postgres is far easier to manage: you can migrate tables to change your data model and easily read it at rest with SQL. Your data is typically already in Postgres – why have a longterm copy in another system just to stream it?

Postgres also allows us to more easily build a ton of useful features, like observability tooling, replays, SQL-based filters on consumers, etc.

While you write directly to your Postgres tables with insert/update/delete, the consumer interface is via HTTP (push or pull). There are a lot of moving parts with message delivery, and we lean on Elixir/OTP to make this smooth.

You can follow along on GitHub, we open source everything: GitHub - sequinstream/sequin: Postgres change data capture to streams, queues, and search indexes like Kafka, SQS, Elasticsearch, HTTP endpoints, and more · GitHub

We have an example with an Elixir+Broadway consumer, which is a great experience:

We also just launched our hosted option, which is a good way to kick the tires.

Finally, I recorded a video yesterday that shows how all this comes together:

Much more to come – let me know if you have any thoughts or questions! We’re adding features all the time, so if we’re missing something, we’d love to hear it :slight_smile:

15
Post #8
acco

acco

Hey all –

Excited to share that we released an Elixir client for Sequin on Hex!

Sequin’s HTTP interface is straightforward enough, but the SDK is a nice wrapper for those that prefer. It’s a good fit if you don’t need a full-blown Broadway producer/pipeline. And you can use the SDK in test to create/delete streams and consumers.

Here’s an example:

# Define your stream and consumer
stream = "your-stream-name"
consumer = "your-consumer-name"

# Send a message
case Sequin.send_message(stream, "test.1", "Hello, Sequin!") do
{:ok, %{published: 1}} ->
  IO.puts("Message sent successfully")

  {:error, error} ->
    IO.puts("Error sending message: #{Exception.message(error)}")
end

# Receive a message
with {:ok, %{message: message, ack_id: ack_id}} <- Sequin.receive_message(stream, consumer),
     :ok <- YourApp.process_message(message),
     :ok <- Sequin.ack_message(stream, consumer, ack_id) do
  IO.puts("Received and acked message: #{inspect(message)}")
else
  {:ok, nil} ->
    IO.puts("No messages available")

  {:error, error} ->
    IO.puts("Error: #{Exception.message(error)}")
end

Let me know if you have any thoughts or questions :pray:

Where Next?

Popular in Announcing Top

wmnnd
Hi there, for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might f...
New
tmbb
PhoenixWS - Websockets over Phoenix Channels Source code on Github here: GitHub - tmbb/phoenix_ws: Websockets implemented over Phoenix Ch...
New
mspanc
I am pleased to announce an initial release of the Membrane Framework - an Elixir-based framework with special focus on processing multim...
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
kip
Image is an image processing library for Elixir. It is based upon the fabulous vix library that provides a libvips wrapper for Elixir. I...
622 18474 194
New
RobertDober
Earmark is a pure-Elixir Markdown converter. It is intended to be used as a library (just call Earmark.as_html), but can also be used as...
239 12560 134
New
mindok
What is ContEx? A pure Elixir server-side data plotting/charting library outputting SVG. It has nice barcharts in particular and works g...
New
josevalim
Hello everyone, We have just released NimbleCSV which is a small and fast CSV parsing library for Elixir. It allows developers to define...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. https://github.com/woylie/doggo Features Unstyled Phoenix components....
New
scohen
Lexical Lexical is a next-generation language server for the Elixir programming language. Features Context aware code completion As-you...
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42920 311
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New

We're in Beta

About us Mission Statement