Build1 distinct publisher3 min readUpdated
A dev.to post on Pion in Go traces a familiar production failure to the tutorial pattern itself: per-request engines, per-connection ECDSA keys, and a UDP port for every viewer.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
A post on dev.to describes a failure mode that anyone who has shipped Pion will recognise: follow the usual Go guides, deploy a WHEP handler, open a handful of player tabs, and the server starts choking [1]. Handshakes stretch to seconds, ICE times out, and half the pprof flame graph is `crypto/elliptic.p256OrdSqr` plus map allocations inside the engine [2].
The pattern under all of it is the one printed in most tutorials: for every POST carrying an SDP offer, construct a new `webrtc.NewAPI()`, register the default codecs, call `api.NewPeerConnection()`, return the answer [3]. On localhost with two clients it flies; in production it does not [4]. The author's read is blunt: many of these guides look like they were never load-tested with even fifty concurrent viewers [5]. The diagnosis is not that WebRTC, Pion or Go is slow, but that expensive global infrastructure is being built per request instead of reused [6].
Three costs are being paid on the request path, and none of them belong there. First, DTLS needs a certificate, which means generating ECDSA P-256 keys through `crypto/ecdsa`, elliptic-curve arithmetic and `crypto/rand` [7]. Second, the engine allocates hundreds of small heap structures for every possible codec, RTCP interceptor, RTP header, header extension and internal component [8]. Third, the stack goes to the OS and opens random UDP ports for ICE candidate gathering and binding, so a typical configuration takes new network resources for each `PeerConnection` [9]. Thirty viewers arriving at once means CPU pinned by key generation, a ballooning connection tracking table, and a garbage collector working through the wreckage of every closed session [10].
The fix described is structural rather than a tuning knob. In the author's own system, RUSEON Core, the heavy work moved into an isolated singleton engine in `internal/webrtc/engine.go` [11]. The certificate is generated once at startup via `ecdsa.GenerateKey(elliptic.P256(), rand.Reader)` [12]; the argument for this is that the browser does not care how old the certificate is, only that the SDP carries a cryptographically valid fingerprint [13]. The codec registry is likewise built at startup and stops touching the heap on every connection [14].
The network change is the one with the most operational consequence. Instead of dozens of random ports, `webrtc.NewICEUDPMux` is attached to a single UDP socket, so one port serves the whole system [15]. The kernel multiplexes incoming STUN, DTLS and SRTP through one file descriptor and Pion sorts packets between ICE and WebRTC sessions in userspace [16]. The claimed result is no port exhaustion and no need to open a 50000-60000 range in the firewall [17], which is a reduction from 10,001 permitted UDP ports to one [19]. That is a firewall rule you can actually defend in a review.
Two caveats about the material. The supplied text carries no before-and-after measurements: no handshake latencies, no CPU figures, no viewer count at which the pooled design was retested [21], so the mechanism is convincing while the magnitude is unverified. And the piece describes both a singleton engine [11] and an engine pool built on `sync.Pool` [18], which are different strategies with different lifetimes; the excerpt is cut off mid-declaration of `WebRTCEnginePool`, so how the two fit together is not shown [20].
What to watch is whether your own handler does the tutorial thing. Grep for `NewAPI()` inside your HTTP path; if it is there, your capacity ceiling is set by ECDSA key generation and socket churn, not by egress.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The author describes a classic side effect of the default Pion WebRTC setup in Go: read the usual Pion usage guides, deploy a WHEP handler, open several browser tabs with the player, and the server starts choking.
Symptoms include handshakes taking seconds, ICE timing out, and half of the pprof flame graph filled with crypto/elliptic.p256OrdSqr and map allocations inside the engine.
On localhost with a couple of clients the per-request approach works fine; in production it turns into a disaster.
The author states the problem is not WebRTC, not Pion (described as a great library) and not Go, but that expensive global infrastructure is created for every single request instead of being reused.
The first expensive operation is generating cryptographic material for DTLS: ECDSA P-256 keys are generated for the DTLS certificate using crypto/ecdsa, heavy elliptic-curve mathematics and randomness from crypto/rand.
The second expensive operation is allocating hundreds of small structures on the heap for all possible codecs, RTCP interceptors, RTP headers, header extensions and other internal components.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Mechanism described in detail, results never measured
The causal story is specific and internally coherent: named Go standard-library calls, named Pion APIs, named repository paths, and a plausible pprof signature. But every quantitative element is missing — no handshake latency, CPU, allocation or GC numbers before or after, no test harness, and the supplied body is truncated mid-section. All of it rests on one self-published account of the author's own code with no independent corroboration.
Only the author's own project
The sole adoption signal is the author describing his own codebase; there is no third-party deployment, release artifact, download or usage figure, and no repository activity data in the supplied material. That is not enough to score adoption.
Modestly overstated: strong framing, unmeasured payoff
The headline framing ('load-bearing bug', 'in production it turns into a disaster', request-to-response reduced to 'a couple of system calls') runs ahead of what is shown, since not one figure supports the improvement and the criticised tutorial pattern is asserted rather than cited. The overstatement is bounded, though: the underlying mechanisms are real and the author explicitly narrows the sync.Pool claim and excludes PeerConnection/DTLS/ICE setup from the 'couple of system calls' figure.
Self-published post showcasing the author's own product
The piece is a first-person developer-blog post whose remedy section is a walkthrough of RUSEON Core internals, so the author benefits from readers accepting both the severity of the problem and the superiority of his architecture. There is no disclosed sponsorship, paywall or vendor pitch, and no commercial ask in the supplied text, which keeps the incentive moderate rather than severe.
Low: single self-interested source, truncated, unmeasured
One publisher, one author, one project, no numbers, and an incomplete body. The architectural direction is credible on mechanism alone, but nothing in the supplied material lets an assessor verify the magnitude of the problem or the fix, or check the trade-offs the post omits.
build
Live video is two protocol decisions, not one, and your CDN is fighting your latency target1 distinct publisher
build
HermitMQ's million-message claim rests on a 29-byte header, not the network1 distinct publisher
build
Your meter now runs on someone else's machine: signed receipts, fsync, and failing open1 distinct publisher
build
A Timed-Out Reset SMS Is Not A Failed One, And Your Retry Code Probably Disagrees1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 17, 2026