https://github.com/maxbolgarin/contem
Zero-dependency drop-in context.Context replacement for graceful shutdown
https://github.com/maxbolgarin/contem
go golang
Last synced: 9 months ago
JSON representation
Zero-dependency drop-in context.Context replacement for graceful shutdown
- Host: GitHub
- URL: https://github.com/maxbolgarin/contem
- Owner: maxbolgarin
- License: mit
- Created: 2024-09-19T05:45:46.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-04-15T18:55:51.000Z (11 months ago)
- Last Synced: 2025-04-15T19:46:08.720Z (11 months ago)
- Topics: go, golang
- Language: Go
- Homepage:
- Size: 55.7 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-go - contem - Drop-in context.Context replacement for graceful shutdown Go applications. (Utilities / Utility/Miscellaneous)
- awesome-go-cn - contem - in context.Context replacement for graceful shutdown Go applications. [![godoc][D]](https://godoc.org/github.com/maxbolgarin/contem) (公用事业公司 / 实用程序/Miscellaneous)
- awesome-go - contem - Drop-in context.Context replacement for graceful shutdown Go applications. (Utilities / Utility/Miscellaneous)
- awesome-go-with-stars - contem - in context.Context replacement for graceful shutdown Go applications. | 2025-08-23 | (Utilities / Utility/Miscellaneous)
- fucking-awesome-go - contem - Drop-in context.Context replacement for graceful shutdown Go applications. (Utilities / Utility/Miscellaneous)
README
# contem - drop-in `context.Context` replacement
[![Go Version][version-img]][doc] [![GoDoc][doc-img]][doc] [![Build][ci-img]][ci] [![GoReport][report-img]][report]

## Overview
`go get -u github.com/maxbolgarin/contem`
**contem** is a zero-dependency drop-in `context.Context` replacement for graceful shutdown. It is lightweight and easy to use: just create a `func run(Context) error { ... }`, where you should `Add` your shutdown methods to the `Context`, and then call `Start` function. **contem** will graceful shutdown and release all added resources with error handling.
* **Graceful shutdown**: your application will process all incoming requests, close all allocated resources and save data from the buffer before exiting.
* **Ctrl+C support**: you can catch `Ctrl+C` signals and gracefully shutdown the application out of the box without remebering how to use `signal.Notify`.
* **Error handling**: you should handle `defer db.Close()` errors to prevent from an unexpected behaviour. With **contem** you just `AddClose` your closer instead of writing `defer func() {...}`.
* **Less code**: you cannot use `log.Fatal()`, because it calls `os.Exit()` and ignores all defer functions. You should write a shutdown code in every `if err != nil {...}` in the main function. With **contem** you can exit right after a shutdown by using `Exit()` option.
* **Handle file close**: how to close a file when an application stops, if it was opened in the internals of your code? Should you return it right to the main or open at the beginning and propogate throught the app? **contem** allows you to add a `File` to the `Context`, than sync and close it during global shutdown.
## Getting Started
You can find some examples [here](examples)
### Example with Start function
```go
func main() {
contem.Start(run, slog.Default())
}
func run(ctx contem.Context) error {
srv := http.Server{Addr: ":8080"}
ctx.Add(srv.Shutdown)
// TODO: add some code
return nil
}
```
You should write an application logic in the `run` function. It should be non blocking. It should init application, start wotrkers in a separate goroutines and returns error in case of initialization failure. **contem** will wait for interrupt signals and then calls `Context.Shutdown`. Run function accepts `Context` as an argument, so you can add shutdown and cancel methods to it.
Here is a full example: [click me](examples/start/main.go)
### Advanced usage
```go
// Step 1. Create context and defer Shutdown
var err error
ctx := contem.New(contem.WithLogger(slog.Default()), contem.Exit(&err))
defer ctx.Shutdown()
// Step 2. Create a server and add server's shutdown method to the context
var server *http.Server
srv, err = server.Start(ctx)
if err != nil {
slog.Error("failed to create server", "error", err)
return
}
ctx.Add(srv.Shutdown)
// Step 3. Wait for the interruption signal
ctx.Wait()
```
What is going on in this snippet of code?
1. Create a `contem.Context` and defer `Shutdown`:
* Pass an error to `Exit` to exit with `1` code if there will be errors in future (you should not use `:=` because it will reassign the error variable and it will exit with `0` code)
* Add `slog` as a logger. It will print `Info` message at the start of shutdown and `Error` message in case of shutdown error. It is useful with `Exit`, because you won't be able to handle error from `Shutdown` in this case.
2. Create a server and add server's shutdown method to the context. You can return from the main without concerns because you have defered `Shutdown` earlier.
3. Wait for the interruption signal. It will block code until `SIGTERM` or `SIGINT` signal is received. After that it will call `Shutdown` and exit the application.
## Contributing
If you'd like to contribute to **contem**, make a fork and submit a pull request. You also can open an issue or text me on Telegram.
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
[LICENSE]: LICENSE.txt
[version-img]: https://img.shields.io/badge/Go-%3E%3D%201.19-%23007d9c
[doc-img]: https://pkg.go.dev/badge/github.com/maxbolgarin/contem
[doc]: https://pkg.go.dev/github.com/maxbolgarin/contem
[ci-img]: https://github.com/maxbolgarin/contem/actions/workflows/go.yml/badge.svg
[ci]: https://github.com/maxbolgarin/contem/actions
[report-img]: https://goreportcard.com/badge/github.com/maxbolgarin/contem
[report]: https://goreportcard.com/report/github.com/maxbolgarin/contem