Supervision
A child service crashes. Detect it, restart it, and stop restarting if it keeps failing. The foundation of fault-tolerant systems.
Hew
Supervisors are a language construct. Three lines per child: restart policy, budget, and strategy. permanent means always restart, transient means restart only on error. budget(5, 60s) caps restarts to 5 within 60 seconds before the supervisor gives up.
supervisor ServiceCluster {
child db: DatabasePool
restart(permanent)
budget(5, 60s)
strategy(one_for_one);
child cache: CacheLayer
restart(permanent);
child api: ApiHandler
restart(transient);
}Erlang/OTP
Erlang invented the supervision model that Hew adopts. The same concepts exist — one_for_one, intensity/period, permanent/transient — but expressed through OTP behaviour callbacks, maps, and tuples rather than language-level declarations.
-module(service_cluster_sup).
-behaviour(supervisor).
-export([start_link/0, init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
SupFlags = #{strategy => one_for_one,
intensity => 5,
period => 60},
Children = [
#{id => db,
start => {database_pool, start_link, []},
restart => permanent,
type => worker},
#{id => cache,
start => {cache_layer, start_link, []},
restart => permanent,
type => worker},
#{id => api,
start => {api_handler, start_link, []},
restart => transient,
type => worker}
],
{ok, {SupFlags, Children}}.Go
Go has no standard supervision pattern. Every team writes their own restart loop. The example below is a simplified version — a production implementation would also need graceful shutdown, time-windowed budgets, and strategy variants.
type Supervisor struct {
maxRestarts int
restarts int
mu sync.Mutex
}
func (s *Supervisor) monitor(name string, start func() error) {
for {
err := start()
if err == nil {
return // Clean exit
}
s.mu.Lock()
s.restarts++
if s.restarts > s.maxRestarts {
s.mu.Unlock()
log.Fatalf("supervisor: %s exceeded restart limit", name)
}
s.mu.Unlock()
log.Printf("supervisor: restarting %s after error: %v", name, err)
}
}
func main() {
sup := &Supervisor{maxRestarts: 5}
go sup.monitor("db", startDatabasePool)
go sup.monitor("cache", startCacheLayer)
go sup.monitor("api", startApiHandler)
select {} // Block forever
}What this shows
Developer experience
Hew brings Erlang's proven supervision model to a statically typed, compiled language with minimal ceremony. Erlang invented the concept but requires module declarations, behaviour callbacks, and configuration maps. Go has no standard supervision — teams write ad-hoc restart loops that often miss edge cases.
Debugging
Hew's supervisor declarations are visible in source code — you can see every child's restart policy at a glance. In Go, supervision logic is scattered through goroutine management code, and it's common for restart limits to be hardcoded constants buried in a different package.
Trade-offs
Erlang's OTP supervision is battle-tested in production for decades at companies like Ericsson and WhatsApp. Hew's supervision is the same model but younger. Go's approach is more explicit — you see exactly what happens on failure, with no framework magic. That explicitness is a feature when debugging unfamiliar code.