<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Phuong Le</title><link>https://func25.dev/</link><description>Recent content on Phuong Le</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sat, 30 May 2026 09:00:00 +0700</lastBuildDate><atom:link href="https://func25.dev/index.xml" rel="self" type="application/rss+xml"/><item><title>Go Runtime Metrics: CPU, GC, Memory, Scheduler</title><link>https://func25.dev/posts/go-runtime-metrics/</link><pubDate>Sat, 30 May 2026 09:00:00 +0700</pubDate><guid>https://func25.dev/posts/go-runtime-metrics/</guid><description>&lt;p>Go exposes many runtime metrics through runtime/metrics, and many metrics clients (&lt;a href="https://github.com/prometheus/client_golang">Prometheus&lt;/a>, &lt;a href="https://github.com/VictoriaMetrics/metrics">VictoriaMetrics&lt;/a>) use it to export Go runtime stats from your application. These metrics include things like:&lt;/p>
&lt;p>how much memory your Go runtime has mapped,&lt;/p>
&lt;p>how much is used by heap objects,&lt;/p>
&lt;p>how much is free,&lt;/p>
&lt;p>how much has been returned to the OS,&lt;/p>
&lt;p>how much time goroutines have spent waiting for mutex locks,&lt;/p>
&lt;p>etc.&lt;/p>
&lt;p>Getting Go runtime stats in a few lines:&lt;/p></description></item><item><title>About</title><link>https://func25.dev/about/</link><pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate><guid>https://func25.dev/about/</guid><description>&lt;p>I&amp;rsquo;m &lt;strong>Phuong Le&lt;/strong> (you&amp;rsquo;ll find me as &lt;strong>@func25&lt;/strong> most places). I&amp;rsquo;m a software engineer at &lt;strong>VictoriaMetrics&lt;/strong>, working on &lt;strong>VictoriaLogs&lt;/strong> — which means I spend my days deep in Go, performance, and storage internals.&lt;/p>
&lt;p>I also write &lt;strong>&lt;a href="https://blog.devtrovert.com/">Devtrovert&lt;/a>&lt;/strong>, where I try to explain backend engineering, system design, and the parts of Go that usually stay hidden — the runtime, the scheduler, defer, the memory model — in a way that&amp;rsquo;s practical rather than academic.&lt;/p></description></item><item><title>Newsletter</title><link>https://func25.dev/newsletter/</link><pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate><guid>https://func25.dev/newsletter/</guid><description>&lt;p>Practical Go, sent when there&amp;rsquo;s something worth saying. Runtime deep dives, performance notes, and patterns that survive contact with production.&lt;/p></description></item><item><title>Privacy</title><link>https://func25.dev/privacy/</link><pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate><guid>https://func25.dev/privacy/</guid><description>&lt;p>This site keeps things simple.&lt;/p>
&lt;h2 id="analytics">Analytics&lt;/h2>
&lt;p>If analytics are enabled, this site uses a privacy-respecting setup with consent: nothing is loaded until you click &lt;strong>Accept&lt;/strong> on the cookie banner. Decline and no analytics cookies are set.&lt;/p>
&lt;h2 id="newsletter">Newsletter&lt;/h2>
&lt;p>If you subscribe, your email address is stored by the newsletter provider solely to send you posts. It is never sold or shared. Every email includes an unsubscribe link.&lt;/p>
&lt;h2 id="contact">Contact&lt;/h2>
&lt;p>Questions? Reach out on &lt;a href="https://x.com/func25">X / Twitter&lt;/a> or &lt;a href="https://github.com/func25">GitHub&lt;/a>.&lt;/p></description></item><item><title>SIGHUP Signal for Configuration Reloads</title><link>https://func25.dev/posts/sighup-config-reloads/</link><pubDate>Wed, 23 Apr 2025 09:00:00 +0700</pubDate><guid>https://func25.dev/posts/sighup-config-reloads/</guid><description>&lt;p>Many applications, including Go applications by default, respond to three signals for termination: &lt;code>SIGTERM&lt;/code>, &lt;code>SIGINT&lt;/code>, and &lt;code>SIGHUP&lt;/code>. Among these, &lt;code>SIGHUP&lt;/code> carries some extra nuances and may be less relevant today.&lt;/p>
&lt;p>By definition:&lt;/p>
&lt;blockquote>
&lt;p>SIGHUP (&amp;ldquo;signal hang up&amp;rdquo;) is a signal sent to a process when its controlling terminal is closed. – Wikipedia&lt;/p>&lt;/blockquote>
&lt;p>But what exactly is a &amp;ldquo;controlling terminal&amp;rdquo;?&lt;/p>
&lt;h2 id="terminal">Terminal&lt;/h2>
&lt;p>Suppose you open a terminal application. This is the window where you see text and type commands. It might be iTerm2, Terminal.app on macOS, or GNOME Terminal on Linux. This window is a graphical interface, but inside it, another program is actually running your commands. That program is usually a shell like bash or zsh.&lt;/p></description></item><item><title>Goroutine Scheduler Revealed: Never See Goroutines the Same Way Again</title><link>https://func25.dev/posts/goroutine-scheduler/</link><pubDate>Tue, 02 Jan 2024 09:00:00 +0700</pubDate><guid>https://func25.dev/posts/goroutine-scheduler/</guid><description>&lt;p>Don&amp;rsquo;t worry about understanding the image above right now, as we&amp;rsquo;re going to begin with the very basics.&lt;/p>
&lt;p>Goroutines are distributed into threads, which Goroutine Scheduler handle behind the scene. From our previous talks, we know a few things about goroutines:&lt;/p>
&lt;ul>
&lt;li>Goroutines in terms of raw execution speed, aren&amp;rsquo;t necessarily faster than threads since they need an actual thread to run on.&lt;/li>
&lt;li>The real advantage of goroutines lies in areas like context switching, memory footprint, the cost of creation and teardown.&lt;/li>
&lt;/ul>
&lt;p>You might have heard of the Goroutine Scheduler before, but how well do we really know how it works? How does it pair goroutines with threads?&lt;/p></description></item><item><title>Go Channels Explained: More than Just a Beginner’s Guide.</title><link>https://func25.dev/posts/go-channels/</link><pubDate>Fri, 29 Dec 2023 09:00:00 +0700</pubDate><guid>https://func25.dev/posts/go-channels/</guid><description>&lt;p>After discussing Goroutines, diving into Goroutines vs OS Threads, examining &lt;code>MAXPROCS&lt;/code> in the previous post, &lt;a href="https://blog.devtrovert.com/p/goroutines-think-you-know-go-basics">Goroutines: Think You Know Go Basics? Think Again&lt;/a>.&lt;/p>
&lt;p>We are now ready to talk about Channels, which act as synchronization points.&lt;/p>
&lt;h3 id="1-channel">1. Channel&lt;/h3>
&lt;p>Imagine a channel as a simple pipe, this pipe connects different goroutines, allowing them to talk to each other by sending data into one end of the pipe and receiving it from the other.&lt;/p></description></item><item><title>Select &amp; For Range Channel in Go: Breaking Down</title><link>https://func25.dev/posts/select-for-range/</link><pubDate>Tue, 26 Dec 2023 09:00:00 +0700</pubDate><guid>https://func25.dev/posts/select-for-range/</guid><description>&lt;p>In our previous discussion, we covered five specific channel types in Go: &lt;a href="https://func25.dev/posts/go-channels/">buffered, unbuffered, directional, nil and closed channels&lt;/a>.&lt;/p>
&lt;p>If you missed that discussion, it&amp;rsquo;s important to note that we identified these types to provide a detailed understanding. Yet, at the most basic level, Go channels are primarily either buffered or unbuffered.&lt;/p>
&lt;p>Now, we&amp;rsquo;re focusing on &lt;code>select&lt;/code> and &lt;code>for range&lt;/code> in Go.&lt;/p>
&lt;h2 id="1-understanding-select">1. Understanding select&lt;/h2>
&lt;p>Basically, the &lt;code>select&lt;/code> statement provides a mechanism for a goroutine to wait on multiple channels using the case statement and its main job is to execute the first case that is ready.&lt;/p></description></item></channel></rss>