nseaSeb

nseaSeb

I’ve just put together a small POC exploring PDF inspection from Elixir/Phoenix:

The idea is pretty simple: drag & drop a PDF in a Phoenix LiveView application, pass it to pdf2md from Firecrawl’s pdf-inspector, and display the extracted information (PDF type, number of pages, tables, Markdown, etc.).

The interesting part for me was not really the PDF processing itself, but how to integrate the Rust component with Elixir.

For this POC, I deliberately avoided a NIF.

Instead, the Rust binary is invoked through an OS Port:

Port.open(
  {:spawn_executable, path},
  [:binary, :exit_status, args: args]
)

The Rust binary is vendored in priv/rust_bin/bin/, so the Phoenix application can invoke it directly.

This feels like a rather nice boundary for this kind of workload:

  • Elixir/Phoenix remains responsible for the application and supervision.

  • Rust does the CPU-heavy/PDF-specific work.

  • No NIF means no risk of blocking or crashing the BEAM VM from native code.

  • The interface between the two sides remains very explicit.

Obviously, there are trade-offs compared with a NIF: process startup, serialization, IPC overhead, error handling, deployment, etc.

So I’m curious about how others in the Elixir ecosystem would approach this.

Would you use an OS Port for this kind of integration, or would you go for a NIF / Rustler?

This is only a POC for now, but I’m particularly interested in feedback on the architecture rather than the PDF extraction itself.

Showing Posts 1 to 8

jc00ke

jc00ke

I think a port is a good option for this, without the downsides of a NIF, mainly that crashes can take down the BEAM. I recently implemented this CNode pattern, which I think is a great option for this kind of interop. In my case, instead of wrapping with Crystal, I used erl_interface directly in my Go and used zig to build the Go project as a CGo binary. I should write that up someday. I never went back to it and never got beyond the PoC “echo”, but I really like the pattern.

nseaSeb

nseaSeb OP

I agree for the port, more latency than nif I guess but can’t crash the beam.

dimitarvp

dimitarvp

Well, anecdotal evidence: I never had a Rust program crash on me.

The only times that actually happened was due to a lack of memory and the Linux OOM reaper killing them.

I do like the architecture though; ports are awesome and in this case when you have an assembly line to process documents, it’s absolutely the better pattern to use – and not super difficult to rework to distributed clusters of nodes, too.

conradwt

conradwt

I like the overall architecture and thanks so much for sharing.

mogery

mogery

Hey! This is a cool project. Disclosure: I work at Firecrawl.

A note regarding crashes: We run pdf-inspector in production on every PDF we encounter via a Node.js native addon (via napi-rs), which has crash characteristics very similar to NIF. We deliberately avoid having any code to the library that can cause panics. :slight_smile:

nseaSeb

nseaSeb OP

Hello, thank you—it’s really nice to receive your comment. I have no doubt that it’s stable; in my opinion, the gain from using Nifs doesn’t matter here, but perhaps I’m mistaken?

derek-zhou

derek-zhou

Crash isolation is only part of the considerations. The others are:

  • Do you need to maintain state at the native side across invocations?
  • Does the native side has a significant async part?
  • Does the native side run for significant amount of time?
dimitarvp

dimitarvp

That question itself made me skip shelling out to Port-s many times in the past btw. But with time I started seeing that with a good orchestrator built on top of Oban / ObanPro you can just update state in the DB f.ex. “job for PDF file blah_blah_173.pdf is still ongoing; this is the remote job ID (can be anything, even Fly.IO VM ID) – check it in 20 minutes and if it’s still not done, kill and retry”.

Of course, orchestration itself is not always as easy but now in the age of LLMs we have multiple excellent offerings in addition to Oban / ObanPro with different tradeoffs for almost every scenario so this is even more readily available than before.

(Though quite honestly, when you have an excellent durable orchestration library that also makes the argument for working inside the BEAM again because your worst-case scenario is to orphan a PDF generation job which is far from the end of the world; you’ll try to find the orphaned file / job and just resume.)

— All posts loaded —

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
AstonJ
Since we have deprecated our Erlang sections (as we have dedicated Erlang Forums now) let’s add this thread for those who’d like to post ...
New
maennchen
:warning: Security advisory: Decimal DoS vulnerability A vulnerability has been published for decimal where very large exponents can cau...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews