Core Concepts: The Start and Stop Lifecycle
Understanding what happens when you call Start() and Stop() is key to using embedded-postgres effectively, especially for managing data and running tests in parallel.
The Start() Lifecycle
When postgres.Start() is called, it performs a sequence of operations to ensure a clean, isolated PostgreSQL instance is ready for use.
-
Port Availability Check: It first checks if the configured port (e.g.,
5432) is available. If another process is listening on that port,Start()will fail immediately. -
Path Management: The library uses several key directories:
CachePath: Where downloaded binary archives (.txzfiles) are stored. Defaults to~/.embedded-postgres-go. This path is persistent across runs.RuntimePath: A temporary directory for the extracted binaries and other runtime files. By default, this directory is deleted and recreated on everyStart()call to ensure a clean slate.DataPath: The PostgreSQL data directory (PGDATA). By default, it's a subdirectory ofRuntimePath, meaning it is also deleted on every start. To persist data between runs, you must configureDataPathto a location outside ofRuntimePath.
-
Binary Acquisition: It ensures the PostgreSQL binaries are available. This is covered in detail in the Binary Management guide.
-
Database Initialization (
initdb): It checks if theDataPathis a valid, initialized PostgreSQL data directory.- If
DataPathis empty or contains data for an incompatible PostgreSQL version, it is wiped, and theinitdbcommand is run to create a new database cluster. - If
DataPathcontains a valid, version-compatible cluster, it is reused. This is how data persistence is achieved.
- If
-
Start PostgreSQL Process: It executes
pg_ctl start, pointing it to the preparedDataPathand passing any customStartParameters. -
Create Initial Database: If the configured database name is not the default
postgres, it connects to the server and runsCREATE DATABASE .... -
Health Check: It repeatedly tries to connect to the new PostgreSQL instance.
Start()only returns successfully once a connection is established and a simple query (SELECT 1) succeeds. If it cannot connect within theStartTimeoutperiod, it returns an error.
The Stop() Lifecycle
Calling postgres.Stop() performs a graceful shutdown of the PostgreSQL process.
- Execute
pg_ctl stop: It runs thepg_ctl stop -wcommand, which waits for the server to shut down cleanly. - Process Cleanup: This ensures no orphaned PostgreSQL processes are left running after your application or test suite finishes.
It is crucial to call Stop() to release resources and ensure a clean exit. A common pattern is to use defer:
postgres := embeddedpostgres.NewDatabase()
if err := postgres.Start(); err != nil {
// handle error
}
defer postgres.Stop()
// ... your test or application logic