Skip to content
web open-source

In-Memory Catalogue Search Service in Go

High-performance Go microservice that holds an in-memory product catalogue snapshot and serves search queries without database round-trips using lock-free atomic pointer swaps.

web │ source only · docker· fly-io· go· postgresql
Docker Fly.io Go PostgreSQL Search Engine

An in-memory product search microservice in Go, serving the Tree Coffee storefront. Postgres remains the source of truth; this service loads a read-only snapshot into RAM and answers every search from memory, with zero database round-trips per query.

Highlights

  • Lock-free reads through an atomic snapshot pointer — the store wraps its snapshot in atomic.Pointer[Snapshot], so readers never take a lock and writers never block them. A refresh builds a whole new snapshot and swaps the pointer, which means there is no torn read and no half-updated catalogue visible to a request mid-swap.
  • A failed refresh keeps serving the old data — if reloading from Postgres fails, the previous snapshot stays in place. The service degrades to stale results instead of returning errors, which is the right failure mode for a search box.
  • The port does not open until the data is there — Bootstrap() retries with backoff and must succeed before the HTTP listener starts, so the service is never reachable in an empty state that would return "no products found" to real customers.
  • Normalisation happens once at load, not per request — name, description, brand and tags are lowercased when the snapshot is built. Doing it per query would repeat the same work on every keystroke of a search-as-you-type box.
  • Tiered ranking that imitates full-text search without a database — exact name match outranks name prefix, which outranks name contains, which outranks word match, which outranks a weak match. It reproduces the useful part of Postgres full-text ranking in memory.
  • Inactive products never enter RAM — the loader filters is_active = true in SQL, so deactivated stock cannot leak into results through a forgotten check in application code.
  • The API DTO is deliberately narrower than the model — flash-sale stock, sold counts and priority exist in the query and the internal model but are intentionally not exposed, so internal merchandising state does not become a public field by accident.

Key Features

  1. Product search endpoint — tiered relevance ranking over the in-memory snapshot, answering without touching Postgres.
  2. Authenticated refresh — POST /admin/refresh rebuilds the snapshot on demand behind a bearer token, so a catalogue change can be published without a redeploy.
  3. Health endpoint — /healthz, wired to Fly.io's 15-second health check.
  4. Snapshot bootstrap with backoff — startup retries until the catalogue loads, then opens the port.
  5. Multi-stage Docker build — a small runtime image produced from a full build stage.
  6. Scale-to-zero deployment — machines auto-stop and auto-start with min_machines_running = 0 on a 512 MB shared-CPU VM.

Tech Stack

  • Go 1.26.4
  • Fiber v2.52 (HTTP framework, on fasthttp)
  • pgx/v5 + pgxpool (Postgres access against Supabase)
  • Docker multi-stage build
  • Fly.io, primary region sin (Singapore)

Status & Maturity

Active, serving both the SvelteKit storefront and the Android app. A single module rather than a monorepo — main.go plus three packages (internal/config, internal/handlers, internal/store) — with no Makefile, no linter and no CI in the repository, so go build, go vet, gofmt -l and go test run manually as the minimum line of defence. The five tests use only the standard library, with no testify and no mocks.

Measured Metrics

Commits 12
Date Range 9 Jul 2026 – 15 Jul 2026
Lines of code 3,120
Tests 5 tests, all passing