vrecan / death Goto Github PK
View Code? Open in Web Editor NEWManaging go application shutdown with signals.
Home Page: https://vreco.fly.dev/blog/post/Concurrent%20Graceful%20Shutdown%20in%20Go
License: MIT License
Managing go application shutdown with signals.
Home Page: https://vreco.fly.dev/blog/post/Concurrent%20Graceful%20Shutdown%20in%20Go
License: MIT License
You need to expose the setLogger and setTimeout methods otherwise I can't change the logger or the timeout.
Context:
> go version
go version go1.15.5
I'm trying to upgrade project vrecan/death
to version v3.0.2
without success.
For instance:
> go get gopkg.in/vrecan/death.v3
go: gopkg.in/vrecan/death.v3 upgrade => v3.0.1+incompatible
โ Not the latest version.
If I try to specify the latest one:
> go get github.com/vrecan/[email protected]
go get github.com/vrecan/[email protected]: github.com/vrecan/[email protected]: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v3
โ it fails.
Though, I found a way to solve this issue using the latest commit on the branch master, but this has some drawbacks.
> go get github.com/vrecan/death@master
go: github.com/vrecan/death master => v0.0.0-20200705210906-920f972a884a
Is there something more I can do?
Thx.
This explains what is allowed as a key in a map.
The language spec defines this precisely, but in short, comparable types are boolean, numeric, string, pointer, channel, and interface types, and structs or arrays that contain only those types.
Below is a test for the issue I'm describing:
type Unhashable map[string]interface{}
func (u Unhashable) Close() error {
return nil
}
Convey("Validate death happens cleanly", t, func() {
u := make(Unhashable)
death := NewDeath(syscall.SIGTERM)
syscall.Kill(os.Getpid(), syscall.SIGTERM)
death.WaitForDeath(u)
})
At the moment death will panic because Unhashable is, well, unhashable, but also an io.Closer. See my suggested solution #17
In summary, it just uses the index of the io.Closer from the internal list of closers. My changes save that index in the closer{} to properly remove from the tracking map.
This library has a hard dependency on github.com/cihub/seelog
. This is useless if we want to use death
in a program that uses another logging package.
So, currently, Death requires the structure you hand it to have a "Close()" method. It would be nice to also be able to register anonymous functions, or even other-named functions with the same traits (no arguments, no return value), for use without having to define a "Close" method for your struct. For that, I propose adding the following definitions:
type closerFunc struct {
f func()
}
func (c *closerFunc) Close() {
c.f()
}
func CloserFunc(f func()) io.Closer {
return &closerFunc{f: f}
}
Now you can make a call like the following:
death.NewDeath(syscall.SIGINT, syscall.SIGTERM).WaitForDeath(CloserFunc(func() {
// do some stuff
// call some other function for cleanup
}))
Or:
type Foo struct {
// stuff
}
func (foo Foo) StopStuff() {
// do stop things
}
func main() {
var foo Foo
death.NewDeath(syscall.SIGINT, syscall.SIGTERM).WaitForDeath(CloserFunc(foo.StopStuff))
}
This lets you hand the WaitForDeath() anonymous functions, non-method functions, and methods with the same signature but a different name, and it'll still see them as io.Closers.
This is the same strategy that the standard library package net/http uses, with its Handler interface (which requires a method with the signature ServeHTTP(ResponseWriter, *Request)
). It defines a second type, HandlerFunc
, that allows you to use anonymous functions or other-named lambdas as a Handler
without having to define a type to hold them.
I am running a badgerDB example for a tutorial that I am working on. I added a network competent that runs with the DB open while receiving RPC from another client. The only way to shut down the client is by issuing a ctrl+c command. Badger has a few issues with windows because it needs to garbage collect its values before exiting. The main problem though is that I can't get windows to gracefully shutdown the program when I execute a ctrl+c break. With Death, the ctrl+c break doesn't even seem to register, instead I have to open task manager and force the process to stop. Is there any way I can work around this or am I just missing something.
Here is what my closeDB function looks like,
func CloseDB(db *badger.DB) {
d := death.NewDeath(syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
d.WaitForDeathWithFunc(func() {
defer runtime.Goexit()
db.Close()
})
}
I am running the runtime.Goexit because there are other defer commands that I want to honor before closing the database and then exiting the program. I've also tried just running NewDeath with syscall.SIGINT or os.Interrupt to no avail.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.