Skip to content

Repository files navigation

TestsLintcodecovLicenseGoDoc

Phase

Phase helps Go applications perform graceful, ordered shutdown — giving you explicit control over how subsystems wind down.

Use Phase to ensure resources are released in the right order: servers stop accepting connections before pipelines drain, and pipelines complete before writing to the database ends.


🚦 Why Phase?

Imagine your app has this data flow:

[ Web API Request ] -> [ Transform Data ] -> [ Persist to DB ]

During shutdown, you want:

  1. The web server to stop accepting new requests
  2. Outstanding work in the transformation queue to finish
  3. Final transformed data to be persisted to the database
  4. The program to exit cleanly

But standard context.Context cancels everything immediately downstream, making it hard to enforce this order. You’d need to manually coordinate dependent goroutines — a recipe for bugs and complexity.

Phase solves this by chaining context lifecycles with parent-child awareness. Shutdown proceeds in reverse order of creation, giving you fine-grained control with a simple API.


🧠 Background

Go’s context.Context is often used to manage cancellation. However, it wasn’t designed for ordered shutdown of interdependent goroutines.

Phase extends this concept by introducing a Phaser — a context with awareness of its children. It gives you a simple interface to create, cancel, wait, and close contexts in a reliable, deterministic order.


✨ Features

  • ✅ Works anywhere a context.Context is accepted
  • 📚 Automatically tracks child phases
  • ⛓ Graceful teardown in reverse order of creation
  • 🧹 Guarantees that cleanup completes before parent exits

🚀 Getting Started

Install:

go get github.com/aelse/phase

Create a root Phaser from any context:

phaser:=phase.FromContext(context.Background())

Spawn child phases using Next():

child:=phaser.Next()

Cancel and wait for shutdown in reverse order:

phase.Cancel(child)
phase.Wait(child)
phase.Close(child)

🔧 Example

package main
import (
"context""fmt""time""github.com/aelse/phase"
)
funcmain() {
// Create root phaserph:=phase.Next(context.Background())
deferphase.Close(ph)
// Each subsystem is a child of the previousweb:=phase.Next(ph)
gocomponent(web, "Web Server")
pipeline:=phase.Next(web)
gocomponent(pipeline, "Data Pipeline")
db:=phase.Next(pipeline)
gocomponent(db, "Database")
fmt.Println("Shutting down in 5 seconds...")
time.Sleep(5*time.Second)
// Start shutdown from rootphase.Cancel(ph)
// Wait for all phases to completephase.Wait(ph)
fmt.Println("All systems shut down.")
}
funccomponent(p phase.Phaser, namestring) {
deferphase.Close(p)
fmt.Printf("[%s] started\n", name)
<-p.Done()
fmt.Printf("[%s] shutting down (wait for children)\n", name)
phase.Wait(p)
fmt.Printf("[%s] shutting down (cleanup)\n", name)
time.Sleep(time.Second)
fmt.Printf("[%s] shutting down\n", name)
}

🔎 See the godoc examples for more complete use cases.

🔁 Alternatives

Projects with similar goals:

  • ash2k/stager
  • skovtunenko/graterm
  • icholy/killable
  • tomb

🪪 License

This project is licensed under the MIT License. See LICENSE for details.

About

Phase provides features to enable systems to perform graceful ordered shutdown.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages